Merge "Use compound drawable instead of image span." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 87d9c14..4175e64e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5885,7 +5885,7 @@
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
- method public java.lang.String getWifiMacAddress();
+ method public java.lang.String getWifiMacAddress(android.content.ComponentName);
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -8142,6 +8142,7 @@
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
field public static final java.lang.String STORAGE_SERVICE = "storage";
+ field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final java.lang.String TELECOM_SERVICE = "telecom";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
@@ -9458,7 +9459,7 @@
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
- method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+ method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
}
@@ -9560,6 +9561,7 @@
method public java.lang.String[] getNames() throws java.io.IOException;
method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+ method public void removeSplit(java.lang.String) throws java.io.IOException;
method public void setStagingProgress(float);
}
@@ -9994,6 +9996,7 @@
method public int getWeight();
method public boolean hasIconFile();
method public boolean hasIconResource();
+ method public boolean hasKeyFieldsOnly();
method public boolean isDynamic();
method public boolean isPinned();
method public void writeToParcel(android.os.Parcel, int);
@@ -10004,6 +10007,7 @@
field public static final int FLAG_DYNAMIC = 1; // 0x1
field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
+ field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
field public static final int FLAG_PINNED = 2; // 0x2
}
@@ -10024,6 +10028,7 @@
method public void deleteAllDynamicShortcuts();
method public void deleteDynamicShortcut(java.lang.String);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+ method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
method public long getRateLimitResetTime();
@@ -12907,7 +12912,8 @@
method public int getGradientType();
method public int getOpacity();
method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
- method public boolean isUseLevel();
+ method public int getShape();
+ method public boolean getUseLevel();
method public void setAlpha(int);
method public void setColor(int);
method public void setColor(android.content.res.ColorStateList);
@@ -19242,24 +19248,6 @@
method public boolean hasFullBiasNanos();
method public boolean hasLeapSecond();
method public boolean hasTimeUncertaintyNanos();
- method public void reset();
- method public void resetBiasNanos();
- method public void resetBiasUncertaintyNanos();
- method public void resetDriftNanosPerSecond();
- method public void resetDriftUncertaintyNanosPerSecond();
- method public void resetFullBiasNanos();
- method public void resetLeapSecond();
- method public void resetTimeUncertaintyNanos();
- method public void set(android.location.GnssClock);
- method public void setBiasNanos(double);
- method public void setBiasUncertaintyNanos(double);
- method public void setDriftNanosPerSecond(double);
- method public void setDriftUncertaintyNanosPerSecond(double);
- method public void setFullBiasNanos(long);
- method public void setHardwareClockDiscontinuityCount(int);
- method public void setLeapSecond(int);
- method public void setTimeNanos(long);
- method public void setTimeUncertaintyNanos(double);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
@@ -19290,31 +19278,6 @@
method public boolean hasCarrierPhaseUncertainty();
method public boolean hasSnrInDb();
method public boolean isPseudorangeRateCorrected();
- method public void reset();
- method public void resetCarrierCycles();
- method public void resetCarrierFrequencyHz();
- method public void resetCarrierPhase();
- method public void resetCarrierPhaseUncertainty();
- method public void resetSnrInDb();
- method public void set(android.location.GnssMeasurement);
- method public void setAccumulatedDeltaRangeMeters(double);
- method public void setAccumulatedDeltaRangeState(int);
- method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
- method public void setCarrierCycles(long);
- method public void setCarrierFrequencyHz(float);
- method public void setCarrierPhase(double);
- method public void setCarrierPhaseUncertainty(double);
- method public void setCn0DbHz(double);
- method public void setConstellationType(int);
- method public void setMultipathIndicator(int);
- method public void setPseudorangeRateMetersPerSecond(double);
- method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
- method public void setReceivedSvTimeNanos(long);
- method public void setReceivedSvTimeUncertaintyNanos(long);
- method public void setSnrInDb(double);
- method public void setState(int);
- method public void setSvid(int);
- method public void setTimeOffsetNanos(double);
method public void writeToParcel(android.os.Parcel, int);
field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
field public static final int ADR_STATE_RESET = 2; // 0x2
@@ -19364,14 +19327,6 @@
method public int getSubmessageId();
method public int getSvid();
method public int getType();
- method public void reset();
- method public void set(android.location.GnssNavigationMessage);
- method public void setData(byte[]);
- method public void setMessageId(int);
- method public void setStatus(int);
- method public void setSubmessageId(int);
- method public void setSvid(int);
- method public void setType(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
field public static final int STATUS_PARITY_PASSED = 1; // 0x1
@@ -20227,37 +20182,129 @@
field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
field public static final java.lang.String TAG_APERTURE = "FNumber";
+ field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
+ field public static final java.lang.String TAG_ARTIST = "Artist";
+ field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+ field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
+ field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
+ field public static final java.lang.String TAG_COLOR_SPACE = "ColorSpace";
+ field public static final java.lang.String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+ field public static final java.lang.String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+ field public static final java.lang.String TAG_COMPRESSION = "Compression";
+ field public static final java.lang.String TAG_CONTRAST = "Contrast";
+ field public static final java.lang.String TAG_COPYRIGHT = "Copyright";
+ field public static final java.lang.String TAG_CUSTOM_RENDERED = "CustomRendered";
field public static final java.lang.String TAG_DATETIME = "DateTime";
field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ field public static final java.lang.String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+ field public static final java.lang.String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+ field public static final java.lang.String TAG_EXIF_VERSION = "ExifVersion";
field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+ field public static final java.lang.String TAG_EXPOSURE_INDEX = "ExposureIndex";
field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
+ field public static final java.lang.String TAG_FILE_SOURCE = "FileSource";
field public static final java.lang.String TAG_FLASH = "Flash";
+ field public static final java.lang.String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+ field public static final java.lang.String TAG_FLASH_ENERGY = "FlashEnergy";
field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
+ field public static final java.lang.String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+ field public static final java.lang.String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+ field public static final java.lang.String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+ field public static final java.lang.String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+ field public static final java.lang.String TAG_F_NUMBER = "FNumber";
+ field public static final java.lang.String TAG_GAIN_CONTROL = "GainControl";
field public static final java.lang.String TAG_GPS_ALTITUDE = "GPSAltitude";
field public static final java.lang.String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
+ field public static final java.lang.String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
field public static final java.lang.String TAG_GPS_DATESTAMP = "GPSDateStamp";
+ field public static final java.lang.String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+ field public static final java.lang.String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+ field public static final java.lang.String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+ field public static final java.lang.String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+ field public static final java.lang.String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+ field public static final java.lang.String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+ field public static final java.lang.String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+ field public static final java.lang.String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+ field public static final java.lang.String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+ field public static final java.lang.String TAG_GPS_DOP = "GPSDOP";
+ field public static final java.lang.String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+ field public static final java.lang.String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
field public static final java.lang.String TAG_GPS_LATITUDE = "GPSLatitude";
field public static final java.lang.String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
field public static final java.lang.String TAG_GPS_LONGITUDE = "GPSLongitude";
field public static final java.lang.String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+ field public static final java.lang.String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+ field public static final java.lang.String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
field public static final java.lang.String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+ field public static final java.lang.String TAG_GPS_SATELLITES = "GPSSatellites";
+ field public static final java.lang.String TAG_GPS_SPEED = "GPSSpeed";
+ field public static final java.lang.String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+ field public static final java.lang.String TAG_GPS_STATUS = "GPSStatus";
field public static final java.lang.String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+ field public static final java.lang.String TAG_GPS_TRACK = "GPSTrack";
+ field public static final java.lang.String TAG_GPS_TRACK_REF = "GPSTrackRef";
+ field public static final java.lang.String TAG_GPS_VERSION_ID = "GPSVersionID";
+ field public static final java.lang.String TAG_IMAGE_DESCRIPTION = "ImageDescription";
field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
+ field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
+ field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+ field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+ field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
field public static final java.lang.String TAG_MAKE = "Make";
+ field public static final java.lang.String TAG_MAKER_NOTE = "MakerNote";
+ field public static final java.lang.String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
field public static final java.lang.String TAG_MODEL = "Model";
+ field public static final java.lang.String TAG_OECF = "OECF";
field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+ field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
+ field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+ field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+ field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+ field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+ field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+ field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+ field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+ field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+ field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
+ field public static final java.lang.String TAG_SATURATION = "Saturation";
+ field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+ field public static final java.lang.String TAG_SCENE_TYPE = "SceneType";
+ field public static final java.lang.String TAG_SENSING_METHOD = "SensingMethod";
+ field public static final java.lang.String TAG_SHARPNESS = "Sharpness";
+ field public static final java.lang.String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+ field public static final java.lang.String TAG_SOFTWARE = "Software";
+ field public static final java.lang.String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+ field public static final java.lang.String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
+ field public static final java.lang.String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+ field public static final java.lang.String TAG_STRIP_OFFSETS = "StripOffsets";
+ field public static final java.lang.String TAG_SUBJECT_AREA = "SubjectArea";
field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+ field public static final java.lang.String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+ field public static final java.lang.String TAG_SUBJECT_LOCATION = "SubjectLocation";
field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
field public static final java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
+ field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
field public static final java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+ field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+ field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+ field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+ field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
+ field public static final java.lang.String TAG_USER_COMMENT = "UserComment";
field public static final java.lang.String TAG_WHITE_BALANCE = "WhiteBalance";
+ field public static final java.lang.String TAG_WHITE_POINT = "WhitePoint";
+ field public static final java.lang.String TAG_X_RESOLUTION = "XResolution";
+ field public static final java.lang.String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+ field public static final java.lang.String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+ field public static final java.lang.String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+ field public static final java.lang.String TAG_Y_RESOLUTION = "YResolution";
field public static final int WHITEBALANCE_AUTO = 0; // 0x0
field public static final int WHITEBALANCE_MANUAL = 1; // 0x1
}
@@ -29080,7 +29127,6 @@
ctor public PersistableBundle();
ctor public PersistableBundle(int);
ctor public PersistableBundle(android.os.PersistableBundle);
- ctor public PersistableBundle(android.os.Bundle);
method public java.lang.Object clone();
method public int describeContents();
method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
@@ -29124,6 +29170,7 @@
public class Process {
ctor public Process();
method public static final long getElapsedCpuTime();
+ method public static final int[] getExclusiveCores();
method public static final int getGidForName(java.lang.String);
method public static final long getStartElapsedRealtime();
method public static final long getStartUptimeMillis();
@@ -29408,6 +29455,147 @@
}
+package android.os.health {
+
+ public class HealthStats {
+ method public java.lang.String getDataType();
+ method public long getMeasurement(int);
+ method public int getMeasurementKeyAt(int);
+ method public int getMeasurementKeyCount();
+ method public java.util.Map<java.lang.String, java.lang.Long> getMeasurements(int);
+ method public int getMeasurementsKeyAt(int);
+ method public int getMeasurementsKeyCount();
+ method public java.util.Map<java.lang.String, android.os.health.HealthStats> getStats(int);
+ method public int getStatsKeyAt(int);
+ method public int getStatsKeyCount();
+ method public android.os.health.TimerStat getTimer(int);
+ method public int getTimerCount(int);
+ method public int getTimerKeyAt(int);
+ method public int getTimerKeyCount();
+ method public long getTimerTime(int);
+ method public java.util.Map<java.lang.String, android.os.health.TimerStat> getTimers(int);
+ method public int getTimersKeyAt(int);
+ method public int getTimersKeyCount();
+ method public boolean hasMeasurement(int);
+ method public boolean hasMeasurements(int);
+ method public boolean hasStats(int);
+ method public boolean hasTimer(int);
+ method public boolean hasTimers(int);
+ }
+
+ public final class PackageHealthStats {
+ field public static final int MEASUREMENTS_WAKEUP_ALARMS_COUNT = 40002; // 0x9c42
+ field public static final int STATS_SERVICES = 40001; // 0x9c41
+ }
+
+ public final class PidHealthStats {
+ field public static final int MEASUREMENT_WAKE_NESTING_COUNT = 20001; // 0x4e21
+ field public static final int MEASUREMENT_WAKE_START_MS = 20003; // 0x4e23
+ field public static final int MEASUREMENT_WAKE_SUM_MS = 20002; // 0x4e22
+ }
+
+ public final class ProcessHealthStats {
+ field public static final int MEASUREMENT_ANR_COUNT = 30005; // 0x7535
+ field public static final int MEASUREMENT_CRASHES_COUNT = 30004; // 0x7534
+ field public static final int MEASUREMENT_FOREGROUND_MS = 30006; // 0x7536
+ field public static final int MEASUREMENT_STARTS_COUNT = 30003; // 0x7533
+ field public static final int MEASUREMENT_SYSTEM_TIME_MS = 30002; // 0x7532
+ field public static final int MEASUREMENT_USER_TIME_MS = 30001; // 0x7531
+ }
+
+ public final class ServiceHealthStats {
+ field public static final int MEASUREMENT_LAUNCH_COUNT = 50002; // 0xc352
+ field public static final int MEASUREMENT_START_SERVICE_COUNT = 50001; // 0xc351
+ }
+
+ public class SystemHealthManager {
+ method public static android.os.health.SystemHealthManager from(android.content.Context);
+ method public android.os.health.HealthStats takeMyUidSnapshot();
+ method public android.os.health.HealthStats takeUidSnapshot(int);
+ method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
+ }
+
+ public class TimerStat implements android.os.Parcelable {
+ ctor public TimerStat();
+ ctor public TimerStat(int, long);
+ ctor public TimerStat(android.os.Parcel);
+ method public int describeContents();
+ method public int getCount();
+ method public long getTime();
+ method public void setCount(int);
+ method public void setTime(long);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.health.TimerStat> CREATOR;
+ }
+
+ public final class UidHealthStats {
+ field public static final int MEASUREMENT_BLUETOOTH_IDLE_MS = 10020; // 0x2724
+ field public static final int MEASUREMENT_BLUETOOTH_POWER_MAMS = 10023; // 0x2727
+ field public static final int MEASUREMENT_BLUETOOTH_RX_BYTES = 10052; // 0x2744
+ field public static final int MEASUREMENT_BLUETOOTH_RX_MS = 10021; // 0x2725
+ field public static final int MEASUREMENT_BLUETOOTH_RX_PACKETS = 10058; // 0x274a
+ field public static final int MEASUREMENT_BLUETOOTH_TX_BYTES = 10053; // 0x2745
+ field public static final int MEASUREMENT_BLUETOOTH_TX_MS = 10022; // 0x2726
+ field public static final int MEASUREMENT_BLUETOOTH_TX_PACKETS = 10059; // 0x274b
+ field public static final int MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT = 10046; // 0x273e
+ field public static final int MEASUREMENT_CPU_POWER_MAUS = 10064; // 0x2750
+ field public static final int MEASUREMENT_MOBILE_IDLE_MS = 10024; // 0x2728
+ field public static final int MEASUREMENT_MOBILE_POWER_MAMS = 10027; // 0x272b
+ field public static final int MEASUREMENT_MOBILE_RX_BYTES = 10048; // 0x2740
+ field public static final int MEASUREMENT_MOBILE_RX_MS = 10025; // 0x2729
+ field public static final int MEASUREMENT_MOBILE_RX_PACKETS = 10054; // 0x2746
+ field public static final int MEASUREMENT_MOBILE_TX_BYTES = 10049; // 0x2741
+ field public static final int MEASUREMENT_MOBILE_TX_MS = 10026; // 0x272a
+ field public static final int MEASUREMENT_MOBILE_TX_PACKETS = 10055; // 0x2747
+ field public static final int MEASUREMENT_OTHER_USER_ACTIVITY_COUNT = 10045; // 0x273d
+ field public static final int MEASUREMENT_REALTIME_BATTERY_MS = 10001; // 0x2711
+ field public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = 10003; // 0x2713
+ field public static final int MEASUREMENT_SYSTEM_CPU_TIME_US = 10063; // 0x274f
+ field public static final int MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT = 10047; // 0x273f
+ field public static final int MEASUREMENT_UPTIME_BATTERY_MS = 10002; // 0x2712
+ field public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = 10004; // 0x2714
+ field public static final int MEASUREMENT_USER_CPU_TIME_US = 10062; // 0x274e
+ field public static final int MEASUREMENT_WIFI_FULL_LOCK_MS = 10029; // 0x272d
+ field public static final int MEASUREMENT_WIFI_IDLE_MS = 10016; // 0x2720
+ field public static final int MEASUREMENT_WIFI_MULTICAST_MS = 10031; // 0x272f
+ field public static final int MEASUREMENT_WIFI_POWER_MAMS = 10019; // 0x2723
+ field public static final int MEASUREMENT_WIFI_RUNNING_MS = 10028; // 0x272c
+ field public static final int MEASUREMENT_WIFI_RX_BYTES = 10050; // 0x2742
+ field public static final int MEASUREMENT_WIFI_RX_MS = 10017; // 0x2721
+ field public static final int MEASUREMENT_WIFI_RX_PACKETS = 10056; // 0x2748
+ field public static final int MEASUREMENT_WIFI_TX_BYTES = 10051; // 0x2743
+ field public static final int MEASUREMENT_WIFI_TX_MS = 10018; // 0x2722
+ field public static final int MEASUREMENT_WIFI_TX_PACKETS = 10057; // 0x2749
+ field public static final int STATS_PACKAGES = 10015; // 0x271f
+ field public static final int STATS_PIDS = 10013; // 0x271d
+ field public static final int STATS_PROCESSES = 10014; // 0x271e
+ field public static final int TIMERS_JOBS = 10010; // 0x271a
+ field public static final int TIMERS_SENSORS = 10012; // 0x271c
+ field public static final int TIMERS_SYNCS = 10009; // 0x2719
+ field public static final int TIMERS_WAKELOCKS_DRAW = 10008; // 0x2718
+ field public static final int TIMERS_WAKELOCKS_FULL = 10005; // 0x2715
+ field public static final int TIMERS_WAKELOCKS_PARTIAL = 10006; // 0x2716
+ field public static final int TIMERS_WAKELOCKS_WINDOW = 10007; // 0x2717
+ field public static final int TIMER_AUDIO = 10032; // 0x2730
+ field public static final int TIMER_BLUETOOTH_SCAN = 10037; // 0x2735
+ field public static final int TIMER_CAMERA = 10035; // 0x2733
+ field public static final int TIMER_FLASHLIGHT = 10034; // 0x2732
+ field public static final int TIMER_FOREGROUND_ACTIVITY = 10036; // 0x2734
+ field public static final int TIMER_GPS_SENSOR = 10011; // 0x271b
+ field public static final int TIMER_MOBILE_RADIO_ACTIVE = 10061; // 0x274d
+ field public static final int TIMER_PROCESS_STATE_BACKGROUND_MS = 10042; // 0x273a
+ field public static final int TIMER_PROCESS_STATE_CACHED_MS = 10043; // 0x273b
+ field public static final int TIMER_PROCESS_STATE_FOREGROUND_MS = 10041; // 0x2739
+ field public static final int TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS = 10039; // 0x2737
+ field public static final int TIMER_PROCESS_STATE_TOP_MS = 10038; // 0x2736
+ field public static final int TIMER_PROCESS_STATE_TOP_SLEEPING_MS = 10040; // 0x2738
+ field public static final int TIMER_VIBRATOR = 10044; // 0x273c
+ field public static final int TIMER_VIDEO = 10033; // 0x2731
+ field public static final int TIMER_WIFI_SCAN = 10030; // 0x272e
+ }
+
+}
+
package android.os.storage {
public abstract class OnObbStateChangeListener {
@@ -57593,6 +57781,17 @@
method public abstract int size();
}
+ public class DoubleSummaryStatistics implements java.util.function.DoubleConsumer {
+ ctor public DoubleSummaryStatistics();
+ method public void accept(double);
+ method public void combine(java.util.DoubleSummaryStatistics);
+ method public final double getAverage();
+ method public final long getCount();
+ method public final double getMax();
+ method public final double getMin();
+ method public final double getSum();
+ }
+
public class DuplicateFormatFlagsException extends java.util.IllegalFormatException {
ctor public DuplicateFormatFlagsException(java.lang.String);
method public java.lang.String getFlags();
@@ -57815,6 +58014,17 @@
ctor public InputMismatchException(java.lang.String);
}
+ public class IntSummaryStatistics implements java.util.function.IntConsumer {
+ ctor public IntSummaryStatistics();
+ method public void accept(int);
+ method public void combine(java.util.IntSummaryStatistics);
+ method public final double getAverage();
+ method public final long getCount();
+ method public final int getMax();
+ method public final int getMin();
+ method public final long getSum();
+ }
+
public class InvalidPropertiesFormatException extends java.io.IOException {
ctor public InvalidPropertiesFormatException(java.lang.Throwable);
ctor public InvalidPropertiesFormatException(java.lang.String);
@@ -58006,6 +58216,18 @@
enum_constant public static final java.util.Locale.Category FORMAT;
}
+ public class LongSummaryStatistics implements java.util.function.IntConsumer java.util.function.LongConsumer {
+ ctor public LongSummaryStatistics();
+ method public void accept(int);
+ method public void accept(long);
+ method public void combine(java.util.LongSummaryStatistics);
+ method public final double getAverage();
+ method public final long getCount();
+ method public final long getMax();
+ method public final long getMin();
+ method public final long getSum();
+ }
+
public abstract interface Map {
method public abstract void clear();
method public abstract boolean containsKey(java.lang.Object);
diff --git a/api/system-current.txt b/api/system-current.txt
index 545a3e0..8e5b99c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6031,7 +6031,7 @@
method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
method public int getUserProvisioningState();
method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
- method public java.lang.String getWifiMacAddress();
+ method public java.lang.String getWifiMacAddress(android.content.ComponentName);
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -8448,6 +8448,7 @@
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
field public static final java.lang.String STORAGE_SERVICE = "storage";
+ field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final java.lang.String TELECOM_SERVICE = "telecom";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
@@ -9792,7 +9793,7 @@
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
- method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+ method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
}
@@ -9894,6 +9895,7 @@
method public java.lang.String[] getNames() throws java.io.IOException;
method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+ method public void removeSplit(java.lang.String) throws java.io.IOException;
method public void setStagingProgress(float);
}
@@ -10388,6 +10390,7 @@
method public int getWeight();
method public boolean hasIconFile();
method public boolean hasIconResource();
+ method public boolean hasKeyFieldsOnly();
method public boolean isDynamic();
method public boolean isPinned();
method public void writeToParcel(android.os.Parcel, int);
@@ -10398,6 +10401,7 @@
field public static final int FLAG_DYNAMIC = 1; // 0x1
field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
+ field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
field public static final int FLAG_PINNED = 2; // 0x2
}
@@ -10418,6 +10422,7 @@
method public void deleteAllDynamicShortcuts();
method public void deleteDynamicShortcut(java.lang.String);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+ method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
method public long getRateLimitResetTime();
@@ -13301,7 +13306,8 @@
method public int getGradientType();
method public int getOpacity();
method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
- method public boolean isUseLevel();
+ method public int getShape();
+ method public boolean getUseLevel();
method public void setAlpha(int);
method public void setColor(int);
method public void setColor(android.content.res.ColorStateList);
@@ -20415,24 +20421,6 @@
method public boolean hasFullBiasNanos();
method public boolean hasLeapSecond();
method public boolean hasTimeUncertaintyNanos();
- method public void reset();
- method public void resetBiasNanos();
- method public void resetBiasUncertaintyNanos();
- method public void resetDriftNanosPerSecond();
- method public void resetDriftUncertaintyNanosPerSecond();
- method public void resetFullBiasNanos();
- method public void resetLeapSecond();
- method public void resetTimeUncertaintyNanos();
- method public void set(android.location.GnssClock);
- method public void setBiasNanos(double);
- method public void setBiasUncertaintyNanos(double);
- method public void setDriftNanosPerSecond(double);
- method public void setDriftUncertaintyNanosPerSecond(double);
- method public void setFullBiasNanos(long);
- method public void setHardwareClockDiscontinuityCount(int);
- method public void setLeapSecond(int);
- method public void setTimeNanos(long);
- method public void setTimeUncertaintyNanos(double);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
}
@@ -20463,31 +20451,6 @@
method public boolean hasCarrierPhaseUncertainty();
method public boolean hasSnrInDb();
method public boolean isPseudorangeRateCorrected();
- method public void reset();
- method public void resetCarrierCycles();
- method public void resetCarrierFrequencyHz();
- method public void resetCarrierPhase();
- method public void resetCarrierPhaseUncertainty();
- method public void resetSnrInDb();
- method public void set(android.location.GnssMeasurement);
- method public void setAccumulatedDeltaRangeMeters(double);
- method public void setAccumulatedDeltaRangeState(int);
- method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
- method public void setCarrierCycles(long);
- method public void setCarrierFrequencyHz(float);
- method public void setCarrierPhase(double);
- method public void setCarrierPhaseUncertainty(double);
- method public void setCn0DbHz(double);
- method public void setConstellationType(int);
- method public void setMultipathIndicator(int);
- method public void setPseudorangeRateMetersPerSecond(double);
- method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
- method public void setReceivedSvTimeNanos(long);
- method public void setReceivedSvTimeUncertaintyNanos(long);
- method public void setSnrInDb(double);
- method public void setState(int);
- method public void setSvid(int);
- method public void setTimeOffsetNanos(double);
method public void writeToParcel(android.os.Parcel, int);
field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
field public static final int ADR_STATE_RESET = 2; // 0x2
@@ -20537,14 +20500,6 @@
method public int getSubmessageId();
method public int getSvid();
method public int getType();
- method public void reset();
- method public void set(android.location.GnssNavigationMessage);
- method public void setData(byte[]);
- method public void setMessageId(int);
- method public void setStatus(int);
- method public void setSubmessageId(int);
- method public void setSvid(int);
- method public void setType(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
field public static final int STATUS_PARITY_PASSED = 1; // 0x1
@@ -21719,37 +21674,129 @@
field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
field public static final java.lang.String TAG_APERTURE = "FNumber";
+ field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
+ field public static final java.lang.String TAG_ARTIST = "Artist";
+ field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+ field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
+ field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
+ field public static final java.lang.String TAG_COLOR_SPACE = "ColorSpace";
+ field public static final java.lang.String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+ field public static final java.lang.String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+ field public static final java.lang.String TAG_COMPRESSION = "Compression";
+ field public static final java.lang.String TAG_CONTRAST = "Contrast";
+ field public static final java.lang.String TAG_COPYRIGHT = "Copyright";
+ field public static final java.lang.String TAG_CUSTOM_RENDERED = "CustomRendered";
field public static final java.lang.String TAG_DATETIME = "DateTime";
field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ field public static final java.lang.String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+ field public static final java.lang.String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+ field public static final java.lang.String TAG_EXIF_VERSION = "ExifVersion";
field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+ field public static final java.lang.String TAG_EXPOSURE_INDEX = "ExposureIndex";
field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
+ field public static final java.lang.String TAG_FILE_SOURCE = "FileSource";
field public static final java.lang.String TAG_FLASH = "Flash";
+ field public static final java.lang.String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+ field public static final java.lang.String TAG_FLASH_ENERGY = "FlashEnergy";
field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
+ field public static final java.lang.String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+ field public static final java.lang.String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+ field public static final java.lang.String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+ field public static final java.lang.String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+ field public static final java.lang.String TAG_F_NUMBER = "FNumber";
+ field public static final java.lang.String TAG_GAIN_CONTROL = "GainControl";
field public static final java.lang.String TAG_GPS_ALTITUDE = "GPSAltitude";
field public static final java.lang.String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
+ field public static final java.lang.String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
field public static final java.lang.String TAG_GPS_DATESTAMP = "GPSDateStamp";
+ field public static final java.lang.String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+ field public static final java.lang.String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+ field public static final java.lang.String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+ field public static final java.lang.String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+ field public static final java.lang.String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+ field public static final java.lang.String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+ field public static final java.lang.String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+ field public static final java.lang.String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+ field public static final java.lang.String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+ field public static final java.lang.String TAG_GPS_DOP = "GPSDOP";
+ field public static final java.lang.String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+ field public static final java.lang.String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
field public static final java.lang.String TAG_GPS_LATITUDE = "GPSLatitude";
field public static final java.lang.String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
field public static final java.lang.String TAG_GPS_LONGITUDE = "GPSLongitude";
field public static final java.lang.String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+ field public static final java.lang.String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+ field public static final java.lang.String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
field public static final java.lang.String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+ field public static final java.lang.String TAG_GPS_SATELLITES = "GPSSatellites";
+ field public static final java.lang.String TAG_GPS_SPEED = "GPSSpeed";
+ field public static final java.lang.String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+ field public static final java.lang.String TAG_GPS_STATUS = "GPSStatus";
field public static final java.lang.String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+ field public static final java.lang.String TAG_GPS_TRACK = "GPSTrack";
+ field public static final java.lang.String TAG_GPS_TRACK_REF = "GPSTrackRef";
+ field public static final java.lang.String TAG_GPS_VERSION_ID = "GPSVersionID";
+ field public static final java.lang.String TAG_IMAGE_DESCRIPTION = "ImageDescription";
field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
+ field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
+ field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+ field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+ field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
field public static final java.lang.String TAG_MAKE = "Make";
+ field public static final java.lang.String TAG_MAKER_NOTE = "MakerNote";
+ field public static final java.lang.String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
field public static final java.lang.String TAG_MODEL = "Model";
+ field public static final java.lang.String TAG_OECF = "OECF";
field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+ field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
+ field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+ field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+ field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+ field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+ field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+ field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+ field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+ field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+ field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
+ field public static final java.lang.String TAG_SATURATION = "Saturation";
+ field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+ field public static final java.lang.String TAG_SCENE_TYPE = "SceneType";
+ field public static final java.lang.String TAG_SENSING_METHOD = "SensingMethod";
+ field public static final java.lang.String TAG_SHARPNESS = "Sharpness";
+ field public static final java.lang.String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+ field public static final java.lang.String TAG_SOFTWARE = "Software";
+ field public static final java.lang.String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+ field public static final java.lang.String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
+ field public static final java.lang.String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+ field public static final java.lang.String TAG_STRIP_OFFSETS = "StripOffsets";
+ field public static final java.lang.String TAG_SUBJECT_AREA = "SubjectArea";
field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+ field public static final java.lang.String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+ field public static final java.lang.String TAG_SUBJECT_LOCATION = "SubjectLocation";
field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
field public static final java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
+ field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
field public static final java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+ field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+ field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+ field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+ field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
+ field public static final java.lang.String TAG_USER_COMMENT = "UserComment";
field public static final java.lang.String TAG_WHITE_BALANCE = "WhiteBalance";
+ field public static final java.lang.String TAG_WHITE_POINT = "WhitePoint";
+ field public static final java.lang.String TAG_X_RESOLUTION = "XResolution";
+ field public static final java.lang.String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+ field public static final java.lang.String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+ field public static final java.lang.String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+ field public static final java.lang.String TAG_Y_RESOLUTION = "YResolution";
field public static final int WHITEBALANCE_AUTO = 0; // 0x0
field public static final int WHITEBALANCE_MANUAL = 1; // 0x1
}
@@ -31360,7 +31407,6 @@
ctor public PersistableBundle();
ctor public PersistableBundle(int);
ctor public PersistableBundle(android.os.PersistableBundle);
- ctor public PersistableBundle(android.os.Bundle);
method public java.lang.Object clone();
method public int describeContents();
method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
@@ -31412,6 +31458,7 @@
public class Process {
ctor public Process();
method public static final long getElapsedCpuTime();
+ method public static final int[] getExclusiveCores();
method public static final int getGidForName(java.lang.String);
method public static final long getStartElapsedRealtime();
method public static final long getStartUptimeMillis();
@@ -31757,6 +31804,147 @@
}
+package android.os.health {
+
+ public class HealthStats {
+ method public java.lang.String getDataType();
+ method public long getMeasurement(int);
+ method public int getMeasurementKeyAt(int);
+ method public int getMeasurementKeyCount();
+ method public java.util.Map<java.lang.String, java.lang.Long> getMeasurements(int);
+ method public int getMeasurementsKeyAt(int);
+ method public int getMeasurementsKeyCount();
+ method public java.util.Map<java.lang.String, android.os.health.HealthStats> getStats(int);
+ method public int getStatsKeyAt(int);
+ method public int getStatsKeyCount();
+ method public android.os.health.TimerStat getTimer(int);
+ method public int getTimerCount(int);
+ method public int getTimerKeyAt(int);
+ method public int getTimerKeyCount();
+ method public long getTimerTime(int);
+ method public java.util.Map<java.lang.String, android.os.health.TimerStat> getTimers(int);
+ method public int getTimersKeyAt(int);
+ method public int getTimersKeyCount();
+ method public boolean hasMeasurement(int);
+ method public boolean hasMeasurements(int);
+ method public boolean hasStats(int);
+ method public boolean hasTimer(int);
+ method public boolean hasTimers(int);
+ }
+
+ public final class PackageHealthStats {
+ field public static final int MEASUREMENTS_WAKEUP_ALARMS_COUNT = 40002; // 0x9c42
+ field public static final int STATS_SERVICES = 40001; // 0x9c41
+ }
+
+ public final class PidHealthStats {
+ field public static final int MEASUREMENT_WAKE_NESTING_COUNT = 20001; // 0x4e21
+ field public static final int MEASUREMENT_WAKE_START_MS = 20003; // 0x4e23
+ field public static final int MEASUREMENT_WAKE_SUM_MS = 20002; // 0x4e22
+ }
+
+ public final class ProcessHealthStats {
+ field public static final int MEASUREMENT_ANR_COUNT = 30005; // 0x7535
+ field public static final int MEASUREMENT_CRASHES_COUNT = 30004; // 0x7534
+ field public static final int MEASUREMENT_FOREGROUND_MS = 30006; // 0x7536
+ field public static final int MEASUREMENT_STARTS_COUNT = 30003; // 0x7533
+ field public static final int MEASUREMENT_SYSTEM_TIME_MS = 30002; // 0x7532
+ field public static final int MEASUREMENT_USER_TIME_MS = 30001; // 0x7531
+ }
+
+ public final class ServiceHealthStats {
+ field public static final int MEASUREMENT_LAUNCH_COUNT = 50002; // 0xc352
+ field public static final int MEASUREMENT_START_SERVICE_COUNT = 50001; // 0xc351
+ }
+
+ public class SystemHealthManager {
+ method public static android.os.health.SystemHealthManager from(android.content.Context);
+ method public android.os.health.HealthStats takeMyUidSnapshot();
+ method public android.os.health.HealthStats takeUidSnapshot(int);
+ method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
+ }
+
+ public class TimerStat implements android.os.Parcelable {
+ ctor public TimerStat();
+ ctor public TimerStat(int, long);
+ ctor public TimerStat(android.os.Parcel);
+ method public int describeContents();
+ method public int getCount();
+ method public long getTime();
+ method public void setCount(int);
+ method public void setTime(long);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.health.TimerStat> CREATOR;
+ }
+
+ public final class UidHealthStats {
+ field public static final int MEASUREMENT_BLUETOOTH_IDLE_MS = 10020; // 0x2724
+ field public static final int MEASUREMENT_BLUETOOTH_POWER_MAMS = 10023; // 0x2727
+ field public static final int MEASUREMENT_BLUETOOTH_RX_BYTES = 10052; // 0x2744
+ field public static final int MEASUREMENT_BLUETOOTH_RX_MS = 10021; // 0x2725
+ field public static final int MEASUREMENT_BLUETOOTH_RX_PACKETS = 10058; // 0x274a
+ field public static final int MEASUREMENT_BLUETOOTH_TX_BYTES = 10053; // 0x2745
+ field public static final int MEASUREMENT_BLUETOOTH_TX_MS = 10022; // 0x2726
+ field public static final int MEASUREMENT_BLUETOOTH_TX_PACKETS = 10059; // 0x274b
+ field public static final int MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT = 10046; // 0x273e
+ field public static final int MEASUREMENT_CPU_POWER_MAUS = 10064; // 0x2750
+ field public static final int MEASUREMENT_MOBILE_IDLE_MS = 10024; // 0x2728
+ field public static final int MEASUREMENT_MOBILE_POWER_MAMS = 10027; // 0x272b
+ field public static final int MEASUREMENT_MOBILE_RX_BYTES = 10048; // 0x2740
+ field public static final int MEASUREMENT_MOBILE_RX_MS = 10025; // 0x2729
+ field public static final int MEASUREMENT_MOBILE_RX_PACKETS = 10054; // 0x2746
+ field public static final int MEASUREMENT_MOBILE_TX_BYTES = 10049; // 0x2741
+ field public static final int MEASUREMENT_MOBILE_TX_MS = 10026; // 0x272a
+ field public static final int MEASUREMENT_MOBILE_TX_PACKETS = 10055; // 0x2747
+ field public static final int MEASUREMENT_OTHER_USER_ACTIVITY_COUNT = 10045; // 0x273d
+ field public static final int MEASUREMENT_REALTIME_BATTERY_MS = 10001; // 0x2711
+ field public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = 10003; // 0x2713
+ field public static final int MEASUREMENT_SYSTEM_CPU_TIME_US = 10063; // 0x274f
+ field public static final int MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT = 10047; // 0x273f
+ field public static final int MEASUREMENT_UPTIME_BATTERY_MS = 10002; // 0x2712
+ field public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = 10004; // 0x2714
+ field public static final int MEASUREMENT_USER_CPU_TIME_US = 10062; // 0x274e
+ field public static final int MEASUREMENT_WIFI_FULL_LOCK_MS = 10029; // 0x272d
+ field public static final int MEASUREMENT_WIFI_IDLE_MS = 10016; // 0x2720
+ field public static final int MEASUREMENT_WIFI_MULTICAST_MS = 10031; // 0x272f
+ field public static final int MEASUREMENT_WIFI_POWER_MAMS = 10019; // 0x2723
+ field public static final int MEASUREMENT_WIFI_RUNNING_MS = 10028; // 0x272c
+ field public static final int MEASUREMENT_WIFI_RX_BYTES = 10050; // 0x2742
+ field public static final int MEASUREMENT_WIFI_RX_MS = 10017; // 0x2721
+ field public static final int MEASUREMENT_WIFI_RX_PACKETS = 10056; // 0x2748
+ field public static final int MEASUREMENT_WIFI_TX_BYTES = 10051; // 0x2743
+ field public static final int MEASUREMENT_WIFI_TX_MS = 10018; // 0x2722
+ field public static final int MEASUREMENT_WIFI_TX_PACKETS = 10057; // 0x2749
+ field public static final int STATS_PACKAGES = 10015; // 0x271f
+ field public static final int STATS_PIDS = 10013; // 0x271d
+ field public static final int STATS_PROCESSES = 10014; // 0x271e
+ field public static final int TIMERS_JOBS = 10010; // 0x271a
+ field public static final int TIMERS_SENSORS = 10012; // 0x271c
+ field public static final int TIMERS_SYNCS = 10009; // 0x2719
+ field public static final int TIMERS_WAKELOCKS_DRAW = 10008; // 0x2718
+ field public static final int TIMERS_WAKELOCKS_FULL = 10005; // 0x2715
+ field public static final int TIMERS_WAKELOCKS_PARTIAL = 10006; // 0x2716
+ field public static final int TIMERS_WAKELOCKS_WINDOW = 10007; // 0x2717
+ field public static final int TIMER_AUDIO = 10032; // 0x2730
+ field public static final int TIMER_BLUETOOTH_SCAN = 10037; // 0x2735
+ field public static final int TIMER_CAMERA = 10035; // 0x2733
+ field public static final int TIMER_FLASHLIGHT = 10034; // 0x2732
+ field public static final int TIMER_FOREGROUND_ACTIVITY = 10036; // 0x2734
+ field public static final int TIMER_GPS_SENSOR = 10011; // 0x271b
+ field public static final int TIMER_MOBILE_RADIO_ACTIVE = 10061; // 0x274d
+ field public static final int TIMER_PROCESS_STATE_BACKGROUND_MS = 10042; // 0x273a
+ field public static final int TIMER_PROCESS_STATE_CACHED_MS = 10043; // 0x273b
+ field public static final int TIMER_PROCESS_STATE_FOREGROUND_MS = 10041; // 0x2739
+ field public static final int TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS = 10039; // 0x2737
+ field public static final int TIMER_PROCESS_STATE_TOP_MS = 10038; // 0x2736
+ field public static final int TIMER_PROCESS_STATE_TOP_SLEEPING_MS = 10040; // 0x2738
+ field public static final int TIMER_VIBRATOR = 10044; // 0x273c
+ field public static final int TIMER_VIDEO = 10033; // 0x2731
+ field public static final int TIMER_WIFI_SCAN = 10030; // 0x272e
+ }
+
+}
+
package android.os.storage {
public abstract class OnObbStateChangeListener {
@@ -60691,6 +60879,17 @@
method public abstract int size();
}
+ public class DoubleSummaryStatistics implements java.util.function.DoubleConsumer {
+ ctor public DoubleSummaryStatistics();
+ method public void accept(double);
+ method public void combine(java.util.DoubleSummaryStatistics);
+ method public final double getAverage();
+ method public final long getCount();
+ method public final double getMax();
+ method public final double getMin();
+ method public final double getSum();
+ }
+
public class DuplicateFormatFlagsException extends java.util.IllegalFormatException {
ctor public DuplicateFormatFlagsException(java.lang.String);
method public java.lang.String getFlags();
@@ -60913,6 +61112,17 @@
ctor public InputMismatchException(java.lang.String);
}
+ public class IntSummaryStatistics implements java.util.function.IntConsumer {
+ ctor public IntSummaryStatistics();
+ method public void accept(int);
+ method public void combine(java.util.IntSummaryStatistics);
+ method public final double getAverage();
+ method public final long getCount();
+ method public final int getMax();
+ method public final int getMin();
+ method public final long getSum();
+ }
+
public class InvalidPropertiesFormatException extends java.io.IOException {
ctor public InvalidPropertiesFormatException(java.lang.Throwable);
ctor public InvalidPropertiesFormatException(java.lang.String);
@@ -61104,6 +61314,18 @@
enum_constant public static final java.util.Locale.Category FORMAT;
}
+ public class LongSummaryStatistics implements java.util.function.IntConsumer java.util.function.LongConsumer {
+ ctor public LongSummaryStatistics();
+ method public void accept(int);
+ method public void accept(long);
+ method public void combine(java.util.LongSummaryStatistics);
+ method public final double getAverage();
+ method public final long getCount();
+ method public final long getMax();
+ method public final long getMin();
+ method public final long getSum();
+ }
+
public abstract interface Map {
method public abstract void clear();
method public abstract boolean containsKey(java.lang.Object);
diff --git a/api/test-current.txt b/api/test-current.txt
index 35b63a2..7fbae97 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5889,7 +5889,7 @@
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
method public android.os.Bundle getUserRestrictions(android.content.ComponentName);
- method public java.lang.String getWifiMacAddress();
+ method public java.lang.String getWifiMacAddress(android.content.ComponentName);
method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -8148,6 +8148,7 @@
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
field public static final java.lang.String STORAGE_SERVICE = "storage";
+ field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final java.lang.String TELECOM_SERVICE = "telecom";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
field public static final java.lang.String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
@@ -9467,7 +9468,7 @@
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
- method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+ method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
}
@@ -9569,6 +9570,7 @@
method public java.lang.String[] getNames() throws java.io.IOException;
method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
+ method public void removeSplit(java.lang.String) throws java.io.IOException;
method public void setStagingProgress(float);
}
@@ -10004,6 +10006,7 @@
method public int getWeight();
method public boolean hasIconFile();
method public boolean hasIconResource();
+ method public boolean hasKeyFieldsOnly();
method public boolean isDynamic();
method public boolean isPinned();
method public void writeToParcel(android.os.Parcel, int);
@@ -10014,6 +10017,7 @@
field public static final int FLAG_DYNAMIC = 1; // 0x1
field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
+ field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
field public static final int FLAG_PINNED = 2; // 0x2
}
@@ -10034,6 +10038,7 @@
method public void deleteAllDynamicShortcuts();
method public void deleteDynamicShortcut(java.lang.String);
method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+ method public int getIconMaxDimensions();
method public int getMaxDynamicShortcutCount();
method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
method public long getRateLimitResetTime();
@@ -12917,7 +12922,8 @@
method public int getGradientType();
method public int getOpacity();
method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
- method public boolean isUseLevel();
+ method public int getShape();
+ method public boolean getUseLevel();
method public void setAlpha(int);
method public void setColor(int);
method public void setColor(android.content.res.ColorStateList);
@@ -19235,6 +19241,7 @@
}
public final class GnssClock implements android.os.Parcelable {
+ ctor public GnssClock();
method public int describeContents();
method public double getBiasNanos();
method public double getBiasUncertaintyNanos();
@@ -19275,6 +19282,7 @@
}
public final class GnssMeasurement implements android.os.Parcelable {
+ ctor public GnssMeasurement();
method public int describeContents();
method public double getAccumulatedDeltaRangeMeters();
method public int getAccumulatedDeltaRangeState();
@@ -19317,6 +19325,7 @@
method public void setCn0DbHz(double);
method public void setConstellationType(int);
method public void setMultipathIndicator(int);
+ method public void setPseudorangeRateCorrected(boolean);
method public void setPseudorangeRateMetersPerSecond(double);
method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
method public void setReceivedSvTimeNanos(long);
@@ -19367,6 +19376,7 @@
}
public final class GnssNavigationMessage implements android.os.Parcelable {
+ ctor public GnssNavigationMessage();
method public int describeContents();
method public byte[] getData();
method public int getMessageId();
@@ -20238,37 +20248,129 @@
field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
field public static final java.lang.String TAG_APERTURE = "FNumber";
+ field public static final java.lang.String TAG_APERTURE_VALUE = "ApertureValue";
+ field public static final java.lang.String TAG_ARTIST = "Artist";
+ field public static final java.lang.String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+ field public static final java.lang.String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
+ field public static final java.lang.String TAG_CFA_PATTERN = "CFAPattern";
+ field public static final java.lang.String TAG_COLOR_SPACE = "ColorSpace";
+ field public static final java.lang.String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+ field public static final java.lang.String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+ field public static final java.lang.String TAG_COMPRESSION = "Compression";
+ field public static final java.lang.String TAG_CONTRAST = "Contrast";
+ field public static final java.lang.String TAG_COPYRIGHT = "Copyright";
+ field public static final java.lang.String TAG_CUSTOM_RENDERED = "CustomRendered";
field public static final java.lang.String TAG_DATETIME = "DateTime";
field public static final java.lang.String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ field public static final java.lang.String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+ field public static final java.lang.String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
field public static final java.lang.String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+ field public static final java.lang.String TAG_EXIF_VERSION = "ExifVersion";
field public static final java.lang.String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+ field public static final java.lang.String TAG_EXPOSURE_INDEX = "ExposureIndex";
field public static final java.lang.String TAG_EXPOSURE_MODE = "ExposureMode";
field public static final java.lang.String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
field public static final java.lang.String TAG_EXPOSURE_TIME = "ExposureTime";
+ field public static final java.lang.String TAG_FILE_SOURCE = "FileSource";
field public static final java.lang.String TAG_FLASH = "Flash";
+ field public static final java.lang.String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+ field public static final java.lang.String TAG_FLASH_ENERGY = "FlashEnergy";
field public static final java.lang.String TAG_FOCAL_LENGTH = "FocalLength";
+ field public static final java.lang.String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+ field public static final java.lang.String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+ field public static final java.lang.String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+ field public static final java.lang.String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+ field public static final java.lang.String TAG_F_NUMBER = "FNumber";
+ field public static final java.lang.String TAG_GAIN_CONTROL = "GainControl";
field public static final java.lang.String TAG_GPS_ALTITUDE = "GPSAltitude";
field public static final java.lang.String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
+ field public static final java.lang.String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
field public static final java.lang.String TAG_GPS_DATESTAMP = "GPSDateStamp";
+ field public static final java.lang.String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+ field public static final java.lang.String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+ field public static final java.lang.String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+ field public static final java.lang.String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+ field public static final java.lang.String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+ field public static final java.lang.String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+ field public static final java.lang.String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+ field public static final java.lang.String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+ field public static final java.lang.String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+ field public static final java.lang.String TAG_GPS_DOP = "GPSDOP";
+ field public static final java.lang.String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+ field public static final java.lang.String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
field public static final java.lang.String TAG_GPS_LATITUDE = "GPSLatitude";
field public static final java.lang.String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
field public static final java.lang.String TAG_GPS_LONGITUDE = "GPSLongitude";
field public static final java.lang.String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+ field public static final java.lang.String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+ field public static final java.lang.String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
field public static final java.lang.String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
+ field public static final java.lang.String TAG_GPS_SATELLITES = "GPSSatellites";
+ field public static final java.lang.String TAG_GPS_SPEED = "GPSSpeed";
+ field public static final java.lang.String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+ field public static final java.lang.String TAG_GPS_STATUS = "GPSStatus";
field public static final java.lang.String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+ field public static final java.lang.String TAG_GPS_TRACK = "GPSTrack";
+ field public static final java.lang.String TAG_GPS_TRACK_REF = "GPSTrackRef";
+ field public static final java.lang.String TAG_GPS_VERSION_ID = "GPSVersionID";
+ field public static final java.lang.String TAG_IMAGE_DESCRIPTION = "ImageDescription";
field public static final java.lang.String TAG_IMAGE_LENGTH = "ImageLength";
+ field public static final java.lang.String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
field public static final java.lang.String TAG_IMAGE_WIDTH = "ImageWidth";
+ field public static final java.lang.String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
field public static final java.lang.String TAG_ISO = "ISOSpeedRatings";
+ field public static final java.lang.String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+ field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+ field public static final java.lang.String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
field public static final java.lang.String TAG_LIGHT_SOURCE = "LightSource";
field public static final java.lang.String TAG_MAKE = "Make";
+ field public static final java.lang.String TAG_MAKER_NOTE = "MakerNote";
+ field public static final java.lang.String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
field public static final java.lang.String TAG_METERING_MODE = "MeteringMode";
field public static final java.lang.String TAG_MODEL = "Model";
+ field public static final java.lang.String TAG_OECF = "OECF";
field public static final java.lang.String TAG_ORIENTATION = "Orientation";
+ field public static final java.lang.String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
+ field public static final java.lang.String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+ field public static final java.lang.String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+ field public static final java.lang.String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+ field public static final java.lang.String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+ field public static final java.lang.String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+ field public static final java.lang.String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+ field public static final java.lang.String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+ field public static final java.lang.String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+ field public static final java.lang.String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
+ field public static final java.lang.String TAG_SATURATION = "Saturation";
+ field public static final java.lang.String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+ field public static final java.lang.String TAG_SCENE_TYPE = "SceneType";
+ field public static final java.lang.String TAG_SENSING_METHOD = "SensingMethod";
+ field public static final java.lang.String TAG_SHARPNESS = "Sharpness";
+ field public static final java.lang.String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+ field public static final java.lang.String TAG_SOFTWARE = "Software";
+ field public static final java.lang.String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+ field public static final java.lang.String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
+ field public static final java.lang.String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+ field public static final java.lang.String TAG_STRIP_OFFSETS = "StripOffsets";
+ field public static final java.lang.String TAG_SUBJECT_AREA = "SubjectArea";
field public static final java.lang.String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+ field public static final java.lang.String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+ field public static final java.lang.String TAG_SUBJECT_LOCATION = "SubjectLocation";
field public static final java.lang.String TAG_SUBSEC_TIME = "SubSecTime";
field public static final java.lang.String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
+ field public static final java.lang.String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
field public static final java.lang.String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+ field public static final java.lang.String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+ field public static final java.lang.String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
+ field public static final java.lang.String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+ field public static final java.lang.String TAG_TRANSFER_FUNCTION = "TransferFunction";
+ field public static final java.lang.String TAG_USER_COMMENT = "UserComment";
field public static final java.lang.String TAG_WHITE_BALANCE = "WhiteBalance";
+ field public static final java.lang.String TAG_WHITE_POINT = "WhitePoint";
+ field public static final java.lang.String TAG_X_RESOLUTION = "XResolution";
+ field public static final java.lang.String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+ field public static final java.lang.String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+ field public static final java.lang.String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+ field public static final java.lang.String TAG_Y_RESOLUTION = "YResolution";
field public static final int WHITEBALANCE_AUTO = 0; // 0x0
field public static final int WHITEBALANCE_MANUAL = 1; // 0x1
}
@@ -29091,7 +29193,6 @@
ctor public PersistableBundle();
ctor public PersistableBundle(int);
ctor public PersistableBundle(android.os.PersistableBundle);
- ctor public PersistableBundle(android.os.Bundle);
method public java.lang.Object clone();
method public int describeContents();
method public android.os.PersistableBundle getPersistableBundle(java.lang.String);
@@ -29135,6 +29236,7 @@
public class Process {
ctor public Process();
method public static final long getElapsedCpuTime();
+ method public static final int[] getExclusiveCores();
method public static final int getGidForName(java.lang.String);
method public static final long getStartElapsedRealtime();
method public static final long getStartUptimeMillis();
@@ -29420,6 +29522,147 @@
}
+package android.os.health {
+
+ public class HealthStats {
+ method public java.lang.String getDataType();
+ method public long getMeasurement(int);
+ method public int getMeasurementKeyAt(int);
+ method public int getMeasurementKeyCount();
+ method public java.util.Map<java.lang.String, java.lang.Long> getMeasurements(int);
+ method public int getMeasurementsKeyAt(int);
+ method public int getMeasurementsKeyCount();
+ method public java.util.Map<java.lang.String, android.os.health.HealthStats> getStats(int);
+ method public int getStatsKeyAt(int);
+ method public int getStatsKeyCount();
+ method public android.os.health.TimerStat getTimer(int);
+ method public int getTimerCount(int);
+ method public int getTimerKeyAt(int);
+ method public int getTimerKeyCount();
+ method public long getTimerTime(int);
+ method public java.util.Map<java.lang.String, android.os.health.TimerStat> getTimers(int);
+ method public int getTimersKeyAt(int);
+ method public int getTimersKeyCount();
+ method public boolean hasMeasurement(int);
+ method public boolean hasMeasurements(int);
+ method public boolean hasStats(int);
+ method public boolean hasTimer(int);
+ method public boolean hasTimers(int);
+ }
+
+ public final class PackageHealthStats {
+ field public static final int MEASUREMENTS_WAKEUP_ALARMS_COUNT = 40002; // 0x9c42
+ field public static final int STATS_SERVICES = 40001; // 0x9c41
+ }
+
+ public final class PidHealthStats {
+ field public static final int MEASUREMENT_WAKE_NESTING_COUNT = 20001; // 0x4e21
+ field public static final int MEASUREMENT_WAKE_START_MS = 20003; // 0x4e23
+ field public static final int MEASUREMENT_WAKE_SUM_MS = 20002; // 0x4e22
+ }
+
+ public final class ProcessHealthStats {
+ field public static final int MEASUREMENT_ANR_COUNT = 30005; // 0x7535
+ field public static final int MEASUREMENT_CRASHES_COUNT = 30004; // 0x7534
+ field public static final int MEASUREMENT_FOREGROUND_MS = 30006; // 0x7536
+ field public static final int MEASUREMENT_STARTS_COUNT = 30003; // 0x7533
+ field public static final int MEASUREMENT_SYSTEM_TIME_MS = 30002; // 0x7532
+ field public static final int MEASUREMENT_USER_TIME_MS = 30001; // 0x7531
+ }
+
+ public final class ServiceHealthStats {
+ field public static final int MEASUREMENT_LAUNCH_COUNT = 50002; // 0xc352
+ field public static final int MEASUREMENT_START_SERVICE_COUNT = 50001; // 0xc351
+ }
+
+ public class SystemHealthManager {
+ method public static android.os.health.SystemHealthManager from(android.content.Context);
+ method public android.os.health.HealthStats takeMyUidSnapshot();
+ method public android.os.health.HealthStats takeUidSnapshot(int);
+ method public android.os.health.HealthStats[] takeUidSnapshots(int[]);
+ }
+
+ public class TimerStat implements android.os.Parcelable {
+ ctor public TimerStat();
+ ctor public TimerStat(int, long);
+ ctor public TimerStat(android.os.Parcel);
+ method public int describeContents();
+ method public int getCount();
+ method public long getTime();
+ method public void setCount(int);
+ method public void setTime(long);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.os.health.TimerStat> CREATOR;
+ }
+
+ public final class UidHealthStats {
+ field public static final int MEASUREMENT_BLUETOOTH_IDLE_MS = 10020; // 0x2724
+ field public static final int MEASUREMENT_BLUETOOTH_POWER_MAMS = 10023; // 0x2727
+ field public static final int MEASUREMENT_BLUETOOTH_RX_BYTES = 10052; // 0x2744
+ field public static final int MEASUREMENT_BLUETOOTH_RX_MS = 10021; // 0x2725
+ field public static final int MEASUREMENT_BLUETOOTH_RX_PACKETS = 10058; // 0x274a
+ field public static final int MEASUREMENT_BLUETOOTH_TX_BYTES = 10053; // 0x2745
+ field public static final int MEASUREMENT_BLUETOOTH_TX_MS = 10022; // 0x2726
+ field public static final int MEASUREMENT_BLUETOOTH_TX_PACKETS = 10059; // 0x274b
+ field public static final int MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT = 10046; // 0x273e
+ field public static final int MEASUREMENT_CPU_POWER_MAUS = 10064; // 0x2750
+ field public static final int MEASUREMENT_MOBILE_IDLE_MS = 10024; // 0x2728
+ field public static final int MEASUREMENT_MOBILE_POWER_MAMS = 10027; // 0x272b
+ field public static final int MEASUREMENT_MOBILE_RX_BYTES = 10048; // 0x2740
+ field public static final int MEASUREMENT_MOBILE_RX_MS = 10025; // 0x2729
+ field public static final int MEASUREMENT_MOBILE_RX_PACKETS = 10054; // 0x2746
+ field public static final int MEASUREMENT_MOBILE_TX_BYTES = 10049; // 0x2741
+ field public static final int MEASUREMENT_MOBILE_TX_MS = 10026; // 0x272a
+ field public static final int MEASUREMENT_MOBILE_TX_PACKETS = 10055; // 0x2747
+ field public static final int MEASUREMENT_OTHER_USER_ACTIVITY_COUNT = 10045; // 0x273d
+ field public static final int MEASUREMENT_REALTIME_BATTERY_MS = 10001; // 0x2711
+ field public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = 10003; // 0x2713
+ field public static final int MEASUREMENT_SYSTEM_CPU_TIME_US = 10063; // 0x274f
+ field public static final int MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT = 10047; // 0x273f
+ field public static final int MEASUREMENT_UPTIME_BATTERY_MS = 10002; // 0x2712
+ field public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = 10004; // 0x2714
+ field public static final int MEASUREMENT_USER_CPU_TIME_US = 10062; // 0x274e
+ field public static final int MEASUREMENT_WIFI_FULL_LOCK_MS = 10029; // 0x272d
+ field public static final int MEASUREMENT_WIFI_IDLE_MS = 10016; // 0x2720
+ field public static final int MEASUREMENT_WIFI_MULTICAST_MS = 10031; // 0x272f
+ field public static final int MEASUREMENT_WIFI_POWER_MAMS = 10019; // 0x2723
+ field public static final int MEASUREMENT_WIFI_RUNNING_MS = 10028; // 0x272c
+ field public static final int MEASUREMENT_WIFI_RX_BYTES = 10050; // 0x2742
+ field public static final int MEASUREMENT_WIFI_RX_MS = 10017; // 0x2721
+ field public static final int MEASUREMENT_WIFI_RX_PACKETS = 10056; // 0x2748
+ field public static final int MEASUREMENT_WIFI_TX_BYTES = 10051; // 0x2743
+ field public static final int MEASUREMENT_WIFI_TX_MS = 10018; // 0x2722
+ field public static final int MEASUREMENT_WIFI_TX_PACKETS = 10057; // 0x2749
+ field public static final int STATS_PACKAGES = 10015; // 0x271f
+ field public static final int STATS_PIDS = 10013; // 0x271d
+ field public static final int STATS_PROCESSES = 10014; // 0x271e
+ field public static final int TIMERS_JOBS = 10010; // 0x271a
+ field public static final int TIMERS_SENSORS = 10012; // 0x271c
+ field public static final int TIMERS_SYNCS = 10009; // 0x2719
+ field public static final int TIMERS_WAKELOCKS_DRAW = 10008; // 0x2718
+ field public static final int TIMERS_WAKELOCKS_FULL = 10005; // 0x2715
+ field public static final int TIMERS_WAKELOCKS_PARTIAL = 10006; // 0x2716
+ field public static final int TIMERS_WAKELOCKS_WINDOW = 10007; // 0x2717
+ field public static final int TIMER_AUDIO = 10032; // 0x2730
+ field public static final int TIMER_BLUETOOTH_SCAN = 10037; // 0x2735
+ field public static final int TIMER_CAMERA = 10035; // 0x2733
+ field public static final int TIMER_FLASHLIGHT = 10034; // 0x2732
+ field public static final int TIMER_FOREGROUND_ACTIVITY = 10036; // 0x2734
+ field public static final int TIMER_GPS_SENSOR = 10011; // 0x271b
+ field public static final int TIMER_MOBILE_RADIO_ACTIVE = 10061; // 0x274d
+ field public static final int TIMER_PROCESS_STATE_BACKGROUND_MS = 10042; // 0x273a
+ field public static final int TIMER_PROCESS_STATE_CACHED_MS = 10043; // 0x273b
+ field public static final int TIMER_PROCESS_STATE_FOREGROUND_MS = 10041; // 0x2739
+ field public static final int TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS = 10039; // 0x2737
+ field public static final int TIMER_PROCESS_STATE_TOP_MS = 10038; // 0x2736
+ field public static final int TIMER_PROCESS_STATE_TOP_SLEEPING_MS = 10040; // 0x2738
+ field public static final int TIMER_VIBRATOR = 10044; // 0x273c
+ field public static final int TIMER_VIDEO = 10033; // 0x2731
+ field public static final int TIMER_WIFI_SCAN = 10030; // 0x272e
+ }
+
+}
+
package android.os.storage {
public abstract class OnObbStateChangeListener {
@@ -57612,6 +57855,17 @@
method public abstract int size();
}
+ public class DoubleSummaryStatistics implements java.util.function.DoubleConsumer {
+ ctor public DoubleSummaryStatistics();
+ method public void accept(double);
+ method public void combine(java.util.DoubleSummaryStatistics);
+ method public final double getAverage();
+ method public final long getCount();
+ method public final double getMax();
+ method public final double getMin();
+ method public final double getSum();
+ }
+
public class DuplicateFormatFlagsException extends java.util.IllegalFormatException {
ctor public DuplicateFormatFlagsException(java.lang.String);
method public java.lang.String getFlags();
@@ -57834,6 +58088,17 @@
ctor public InputMismatchException(java.lang.String);
}
+ public class IntSummaryStatistics implements java.util.function.IntConsumer {
+ ctor public IntSummaryStatistics();
+ method public void accept(int);
+ method public void combine(java.util.IntSummaryStatistics);
+ method public final double getAverage();
+ method public final long getCount();
+ method public final int getMax();
+ method public final int getMin();
+ method public final long getSum();
+ }
+
public class InvalidPropertiesFormatException extends java.io.IOException {
ctor public InvalidPropertiesFormatException(java.lang.Throwable);
ctor public InvalidPropertiesFormatException(java.lang.String);
@@ -58025,6 +58290,18 @@
enum_constant public static final java.util.Locale.Category FORMAT;
}
+ public class LongSummaryStatistics implements java.util.function.IntConsumer java.util.function.LongConsumer {
+ ctor public LongSummaryStatistics();
+ method public void accept(int);
+ method public void accept(long);
+ method public void combine(java.util.LongSummaryStatistics);
+ method public final double getAverage();
+ method public final long getCount();
+ method public final long getMax();
+ method public final long getMin();
+ method public final long getSum();
+ }
+
public abstract interface Map {
method public abstract void clear();
method public abstract boolean containsKey(java.lang.Object);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a452d20..d8bc119 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3722,10 +3722,9 @@
} catch (RemoteException ex) {
if (ex instanceof TransactionTooLargeException
&& activity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
- Log.e(TAG, "App tried sending too much data in instance state", ex);
+ Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
return;
}
-
throw ex.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index bbf1607..83dc506 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -125,9 +125,8 @@
@Nullable OnDateSetListener listener, int year, int month, int dayOfMonth) {
this(context, themeResId);
- mDateSetListener = listener;
-
mDatePicker.updateDate(year, month, dayOfMonth);
+ mDateSetListener = listener;
}
static @StyleRes int resolveDialogTheme(@NonNull Context context, @StyleRes int themeResId) {
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 2c270fc..7a69c62 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -61,7 +61,7 @@
StatusBarNotification[] getActiveNotifications(String callingPkg);
StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
- void registerListener(in INotificationListener listener, in ComponentName component, int userid, boolean asRanker);
+ void registerListener(in INotificationListener listener, in ComponentName component, int userid);
void unregisterListener(in INotificationListener listener, int userid);
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 7cfa0cd..10aa7eb 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -145,7 +145,6 @@
public static final String ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL
= "android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL";
-
/** @hide */
@IntDef({INTERRUPTION_FILTER_NONE, INTERRUPTION_FILTER_PRIORITY, INTERRUPTION_FILTER_ALARMS,
INTERRUPTION_FILTER_ALL, INTERRUPTION_FILTER_UNKNOWN})
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3a5dd30..6c0b69c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -103,6 +103,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.Vibrator;
+import android.os.health.SystemHealthManager;
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
@@ -273,9 +274,9 @@
}});
registerService(Context.DROPBOX_SERVICE, DropBoxManager.class,
- new StaticServiceFetcher<DropBoxManager>() {
+ new CachedServiceFetcher<DropBoxManager>() {
@Override
- public DropBoxManager createService() {
+ public DropBoxManager createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.DROPBOX_SERVICE);
IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
if (service == null) {
@@ -285,7 +286,7 @@
// DROPBOX_SERVICE is registered.
return null;
}
- return new DropBoxManager(service);
+ return new DropBoxManager(ctx, service);
}});
registerService(Context.INPUT_SERVICE, InputManager.class,
@@ -747,18 +748,23 @@
@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));
}});
registerService(Context.SHORTCUT_SERVICE, ShortcutManager.class,
new CachedServiceFetcher<ShortcutManager>() {
- @Override
- public ShortcutManager createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(Context.SHORTCUT_SERVICE);
- return new ShortcutManager(ctx,
- IShortcutService.Stub.asInterface(b));
- }});
+ @Override
+ public ShortcutManager createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(Context.SHORTCUT_SERVICE);
+ return new ShortcutManager(ctx, IShortcutService.Stub.asInterface(b));
+ }});
+
+ registerService(Context.SYSTEM_HEALTH_SERVICE, SystemHealthManager.class,
+ new CachedServiceFetcher<SystemHealthManager>() {
+ @Override
+ public SystemHealthManager createService(ContextImpl ctx) {
+ return new SystemHealthManager();
+ }});
}
/**
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6bc03f7..2d06dcc 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -49,7 +49,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.view.WindowManagerGlobal;
@@ -263,7 +262,8 @@
static class Globals extends IWallpaperManagerCallback.Stub {
private IWallpaperManager mService;
- private Bitmap mWallpaper;
+ private Bitmap mCachedWallpaper;
+ private int mCachedWallpaperUserId;
private Bitmap mDefaultWallpaper;
Globals(Looper looper) {
@@ -296,33 +296,34 @@
throw e.rethrowFromSystemServer();
}
}
- if (mWallpaper != null) {
- return mWallpaper;
+ if (mCachedWallpaper != null && mCachedWallpaperUserId == userId) {
+ return mCachedWallpaper;
}
- if (mDefaultWallpaper != null) {
- return mDefaultWallpaper;
- }
- mWallpaper = null;
+ mCachedWallpaper = null;
+ mCachedWallpaperUserId = 0;
try {
- mWallpaper = getCurrentWallpaperLocked(userId);
+ mCachedWallpaper = getCurrentWallpaperLocked(userId);
+ mCachedWallpaperUserId = userId;
} catch (OutOfMemoryError e) {
Log.w(TAG, "No memory load current wallpaper", e);
}
- if (returnDefault) {
- if (mWallpaper == null) {
- mDefaultWallpaper = getDefaultWallpaperLocked(context);
- return mDefaultWallpaper;
- } else {
- mDefaultWallpaper = null;
- }
+ if (mCachedWallpaper != null) {
+ return mCachedWallpaper;
}
- return mWallpaper;
+ if (returnDefault) {
+ if (mDefaultWallpaper == null) {
+ mDefaultWallpaper = getDefaultWallpaperLocked(context);
+ }
+ return mDefaultWallpaper;
+ }
+ return null;
}
}
public void forgetLoadedWallpaper() {
synchronized (this) {
- mWallpaper = null;
+ mCachedWallpaper = null;
+ mCachedWallpaperUserId = 0;
mDefaultWallpaper = null;
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c4037f8..af9705f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2774,18 +2774,19 @@
* certificate and corresponding private key. All apps within the profile will be able to access
* the certificate and use the private key, given direct user approval.
*
- * <p>The caller of this API may grant itself access to the credential immediately, without user
- * approval. It is a best practice not to request this unless strictly necessary since it opens
- * up additional security vulnerabilities.
+ * <p>The caller of this API may grant itself access to the certificate and private key
+ * immediately, without user approval. It is a best practice not to request this unless strictly
+ * necessary since it opens up additional security vulnerabilities.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if calling from a delegated certificate installer.
+ * {@code null} if calling from a delegated certificate installer.
* @param privKey The private key to install.
* @param cert The certificate to install.
* @param alias The private key alias under which to install the certificate. If a certificate
- * with that alias already exists, it will be overwritten.
+ * with that alias already exists, it will be overwritten.
* @param requestAccess {@code true} to request that the calling app be granted access to the
- * credentials immediately. Otherwise, access to the credentials will be gated by user approval.
+ * credentials immediately. Otherwise, access to the credentials will be gated by user
+ * approval.
* @return {@code true} if the keys were installed, {@code false} otherwise.
*/
public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
@@ -2806,13 +2807,13 @@
}
/**
- * Called by a device or profile owner, or delegated certificate installer, to remove all user
- * credentials installed under a given alias.
+ * Called by a device or profile owner, or delegated certificate installer, to remove a
+ * certificate and private key pair installed under a given alias.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
- * {@code null} if calling from a delegated certificate installer.
+ * {@code null} if calling from a delegated certificate installer.
* @param alias The private key alias under which the certificate is installed.
- * @return {@code true} if the certificate alias no longer exists, {@code false} otherwise.
+ * @return {@code true} if the private key alias no longer exists, {@code false} otherwise.
*/
public boolean removeKeyPair(@Nullable ComponentName admin, @NonNull String alias) {
try {
@@ -5542,14 +5543,15 @@
/**
* Called by device owner to get the MAC address of the Wi-Fi device.
*
+ * @param admin Which device owner this request is associated with.
* @return the MAC address of the Wi-Fi device, or null when the information is not
* available. (For example, Wi-Fi hasn't been enabled, or the device doesn't support Wi-Fi.)
*
* <p>The address will be in the {@code XX:XX:XX:XX:XX:XX} format.
*/
- public String getWifiMacAddress() {
+ public String getWifiMacAddress(@NonNull ComponentName admin) {
try {
- return mService.getWifiMacAddress();
+ return mService.getWifiMacAddress(admin);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 8cdfee5..61b40d4 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -16,6 +16,8 @@
package android.app.admin;
+import android.os.UserHandle;
+
import java.util.List;
/**
@@ -71,8 +73,8 @@
public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
/**
- * Checks if a given package has a device or a profile owner for the given user
- *
+ * Checks if a given package has a device or a profile owner for the given user.
+ * </br><em>Does <b>not</b> support negative userIds like {@link UserHandle#USER_ALL}</em>
* @param packageName The package to check
* @param userId the userId to check for.
* @return true if package has a device or profile owner, false otherwise.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b7a16aa..dc73e26 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -262,7 +262,7 @@
List<String> getKeepUninstalledPackages(in ComponentName admin);
boolean isManagedProfile(in ComponentName admin);
boolean isSystemOnlyUser(in ComponentName admin);
- String getWifiMacAddress();
+ String getWifiMacAddress(in ComponentName admin);
void reboot(in ComponentName admin);
void setShortSupportMessage(in ComponentName admin, in String message);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f96ddf0..825dd5b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3585,6 +3585,15 @@
public static final String SHORTCUT_SERVICE = "shortcut";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.os.health.SystemHealthManager} for accessing system health (battery, power,
+ * memory, etc) metrics.
+ *
+ * @see #getSystemService
+ */
+ public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index da3c873..b1d3f20 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -26,6 +26,8 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
+import android.os.ParcelFileDescriptor;
+
import java.util.List;
/**
@@ -50,6 +52,10 @@
in UserHandle user);
void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
in UserHandle user);
- void startShortcut(String callingPackage, in ShortcutInfo shortcut, in Rect sourceBounds,
- in Bundle startActivityOptions, in UserHandle user);
+ boolean startShortcut(String callingPackage, String packageName, String id,
+ in Rect sourceBounds, in Bundle startActivityOptions, in UserHandle user);
+
+ int getShortcutIconResId(String callingPackage, in ShortcutInfo shortcut, in UserHandle user);
+ ParcelFileDescriptor getShortcutIconFd(String callingPackage, in ShortcutInfo shortcut,
+ in UserHandle user);
}
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index aee3ba7..2a3fac3 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -29,6 +29,8 @@
ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
ParcelFileDescriptor openRead(String name);
+ void removeSplit(String splitName);
+
void close();
void commit(in IntentSender statusReceiver);
void abandon();
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 23e671d..8f9dcfc 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -44,5 +44,7 @@
long getRateLimitResetTime(String packageName, int userId);
+ int getIconMaxDimensions(String packageName, int userId);
+
void resetThrottling(); // system only API for developer opsions
}
\ No newline at end of file
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index f05ecd3..a6a732e 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -183,7 +183,8 @@
public static final int FLAG_GET_PINNED = 1 << 1;
/**
- * Requests "key" fields only.
+ * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()} for which
+ * fields are available.
*/
public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
@@ -473,7 +474,11 @@
*/
@RequiresPermission(permission.BIND_APPWIDGET)
public int getShortcutIconResId(@NonNull ShortcutInfo shortcut, @NonNull UserHandle user) {
- throw new RuntimeException("not implemented yet");
+ try {
+ return mService.getShortcutIconResId(mContext.getPackageName(), shortcut, user);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -488,7 +493,11 @@
@RequiresPermission(permission.BIND_APPWIDGET)
public ParcelFileDescriptor getShortcutIconFd(
@NonNull ShortcutInfo shortcut, @NonNull UserHandle user) {
- throw new RuntimeException("not implemented yet");
+ try {
+ return mService.getShortcutIconFd(mContext.getPackageName(), shortcut, user);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -496,18 +505,21 @@
*
* <p>Callers mut have the {@link permission#BIND_APPWIDGET} permission.
*
- * @param shortcut The target shortcut.
+ * @param packageName The target shortcut package name.
+ * @param shortcutId The target shortcut ID.
* @param sourceBounds The Rect containing the source bounds of the clicked icon.
* @param startActivityOptions Options to pass to startActivity.
* @param user The UserHandle of the profile.
+ * @return {@code false} when the shortcut is no longer valid (e.g. the creator application
+ * has been uninstalled). {@code true} when the shortcut is still valid.
*/
@RequiresPermission(permission.BIND_APPWIDGET)
- public void startShortcut(@NonNull ShortcutInfo shortcut,
+ public boolean startShortcut(@NonNull String packageName, @NonNull String shortcutId,
@Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
@NonNull UserHandle user) {
try {
- mService.startShortcut(mContext.getPackageName(), shortcut, sourceBounds,
- startActivityOptions, user);
+ return mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
+ sourceBounds, startActivityOptions, user);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 700a40d..ec536e0 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -795,6 +795,27 @@
}
/**
+ * Removes a split.
+ * <p>
+ * Split removals occur prior to adding new APKs. If upgrading a feature
+ * split, it is not expected nor desirable to remove the split prior to
+ * upgrading.
+ * <p>
+ * When split removal is bundled with new APKs, the packageName must be
+ * identical.
+ */
+ public void removeSplit(@NonNull String splitName) throws IOException {
+ try {
+ mSession.removeSplit(splitName);
+ } catch (RuntimeException e) {
+ ExceptionUtils.maybeUnwrapIOException(e);
+ throw e;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Attempt to commit everything staged in this session. This may require
* user intervention, and so it may not happen immediately. The final
* result of the commit will be reported through the given callback.
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 6520563..83a70cd 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -19,9 +19,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -60,6 +62,9 @@
/* @hide */
public static final int FLAG_HAS_ICON_FILE = 1 << 3;
+ /* @hide */
+ public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
+
/** @hide */
@IntDef(flag = true,
value = {
@@ -67,6 +72,7 @@
FLAG_PINNED,
FLAG_HAS_ICON_RES,
FLAG_HAS_ICON_FILE,
+ FLAG_KEY_FIELDS_ONLY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ShortcutFlags {}
@@ -114,10 +120,15 @@
@NonNull
private String mTitle;
+ /**
+ * Intent *with extras removed*.
+ */
@NonNull
private Intent mIntent;
- // Internal use only.
+ /**
+ * Extras for the intent.
+ */
@NonNull
private PersistableBundle mIntentPersistableExtras;
@@ -149,6 +160,11 @@
mIcon = b.mIcon;
mTitle = b.mTitle;
mIntent = b.mIntent;
+ final Bundle intentExtras = mIntent.getExtras();
+ if (intentExtras != null) {
+ mIntent.replaceExtras((Bundle) null);
+ mIntentPersistableExtras = new PersistableBundle(intentExtras);
+ }
mWeight = b.mWeight;
mExtras = b.mExtras;
updateTimestamp();
@@ -170,11 +186,12 @@
private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) {
mId = source.mId;
mPackageName = source.mPackageName;
- mActivityComponent = source.mActivityComponent;
mFlags = source.mFlags;
mLastChangedTimestamp = source.mLastChangedTimestamp;
if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
+ mActivityComponent = source.mActivityComponent;
+
if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
mIcon = source.mIcon;
}
@@ -188,6 +205,10 @@
mExtras = source.mExtras;
mIconResourceId = source.mIconResourceId;
mBitmapPath = source.mBitmapPath;
+
+ } else {
+ // Set this bit.
+ mFlags |= FLAG_KEY_FIELDS_ONLY;
}
}
@@ -239,6 +260,39 @@
}
/**
+ * @hide
+ */
+ public static Icon validateIcon(Icon icon) {
+ switch (icon.getType()) {
+ case Icon.TYPE_RESOURCE:
+ case Icon.TYPE_BITMAP:
+ break; // OK
+ case Icon.TYPE_URI:
+ if (ContentResolver.SCHEME_CONTENT.equals(icon.getUri().getScheme())) {
+ break;
+ }
+ // Note "file:" is not supported, because depending on the path, system server
+ // cannot access it. // TODO Revisit "file:" icon support
+
+ // fall through
+ default:
+ throw getInvalidIconException();
+ }
+ if (icon.hasTint()) {
+ // TODO support it
+ throw new IllegalArgumentException("Icons with tints are not supported");
+ }
+
+ return icon;
+ }
+
+ /** @hide */
+ public static IllegalArgumentException getInvalidIconException() {
+ return new IllegalArgumentException("Unsupported icon type:"
+ +" only bitmap, resource and content URI are supported");
+ }
+
+ /**
* Builder class for {@link ShortcutInfo} objects.
*/
public static class Builder {
@@ -273,7 +327,9 @@
}
/**
- * Optionally sets the target activity.
+ * Optionally sets the target activity. If it's not set, and if the caller application
+ * has multiple launcher icons, this shortcut will be shown on all those icons.
+ * If it's set, this shortcut will be only shown on this activity.
*/
@NonNull
public Builder setActivityComponent(@NonNull ComponentName activityComponent) {
@@ -284,15 +340,22 @@
/**
* Optionally sets an icon.
*
- * - Tint is not supported TODO Either check and throw, or support it.
- * - URI icons will be converted into Bitmap icons at the registration time.
+ * <ul>
+ * <li>Tints are not supported.
+ * <li>Bitmaps, resources and "content:" URIs are supported.
+ * <li>"content:" URI will be fetched when a shortcut is registered to
+ * {@link ShortcutManager}. Changing the content from the same URI later will
+ * not be reflected to launcher icons.
+ * </ul>
*
- * TODO Only allow Bitmap, Resource and URI types. byte[] type can easily go over
- * binder size limit.
+ * <p>For performance reasons, icons will <b>NOT</b> be available on instances
+ * returned by {@link ShortcutManager} or {@link LauncherApps}. Launcher applications
+ * need to use {@link LauncherApps#getShortcutIconFd(ShortcutInfo, UserHandle)}
+ * and {@link LauncherApps#getShortcutIconResId(ShortcutInfo, UserHandle)}.
*/
@NonNull
public Builder setIcon(Icon icon) {
- mIcon = icon;
+ mIcon = validateIcon(icon);
return this;
}
@@ -316,7 +379,7 @@
}
/**
- * Optionally sets the weight of a shortcut, which will be used by Launcher for sorting.
+ * Optionally sets the weight of a shortcut, which will be used by the launcher for sorting.
* The larger the weight, the more "important" a shortcut is.
*/
@NonNull
@@ -326,8 +389,8 @@
}
/**
- * Optional values that application can set.
- * TODO: reserve keys starting with "android."
+ * Optional values that applications can set. Applications can store any meta-data of
+ * shortcuts in this, and retrieve later from {@link ShortcutInfo#getExtras()}.
*/
@NonNull
public Builder setExtras(@NonNull PersistableBundle extras) {
@@ -353,7 +416,7 @@
}
/**
- * Return the ID of the shortcut.
+ * Return the package name of the creator application.
*/
@NonNull
public String getPackageName() {
@@ -374,7 +437,7 @@
*
* For performance reasons, this will <b>NOT</b> be available when an instance is returned
* by {@link ShortcutManager} or {@link LauncherApps}. A launcher application needs to use
- * other APIs in LauncherApps to fetch the bitmap. TODO Add a precondition for it.
+ * other APIs in LauncherApps to fetch the bitmap.
*
* @hide
*/
@@ -385,22 +448,46 @@
/**
* Return the shortcut title.
+ *
+ * <p>All shortcuts must have a non-empty title, but this method will return null when
+ * {@link #hasKeyFieldsOnly()} is true.
*/
- @NonNull
+ @Nullable
public String getTitle() {
return mTitle;
}
/**
* Return the intent.
- * TODO Set mIntentPersistableExtras and before returning.
+ *
+ * <p>All shortcuts must have an intent, but this method will return null when
+ * {@link #hasKeyFieldsOnly()} is true.
*/
- @NonNull
+ @Nullable
public Intent getIntent() {
+ if (mIntent == null) {
+ return null;
+ }
+ final Intent intent = new Intent(mIntent);
+ intent.replaceExtras(
+ mIntentPersistableExtras != null ? new Bundle(mIntentPersistableExtras) : null);
+ return intent;
+ }
+
+ /**
+ * Return "raw" intent, which is the original intent without the extras.
+ * @hide
+ */
+ @Nullable
+ public Intent getIntentNoExtras() {
return mIntent;
}
- /** @hide */
+ /**
+ * The extras in the intent. We convert extras into {@link PersistableBundle} so we can
+ * persist them.
+ * @hide
+ */
@Nullable
public PersistableBundle getIntentPersistableExtras() {
return mIntentPersistableExtras;
@@ -483,6 +570,23 @@
return hasFlags(FLAG_HAS_ICON_FILE);
}
+ /**
+ * Return whether a shortcut only contains "key" information only or not. If true, only the
+ * following fields are available.
+ * <ul>
+ * <li>{@link #getId()}
+ * <li>{@link #getPackageName()}
+ * <li>{@link #getLastChangedTimestamp()}
+ * <li>{@link #isDynamic()}
+ * <li>{@link #isPinned()}
+ * <li>{@link #hasIconResource()}
+ * <li>{@link #hasIconFile()}
+ * </ul>
+ */
+ public boolean hasKeyFieldsOnly() {
+ return hasFlags(FLAG_KEY_FIELDS_ONLY);
+ }
+
/** @hide */
public void updateTimestamp() {
mLastChangedTimestamp = System.currentTimeMillis();
@@ -495,33 +599,13 @@
}
/** @hide */
- public void setIcon(Icon icon) {
- mIcon = icon;
+ public void clearIcon() {
+ mIcon = null;
}
/** @hide */
- public void setTitle(String title) {
- mTitle = title;
- }
-
- /** @hide */
- public void setIntent(Intent intent) {
- mIntent = intent;
- }
-
- /** @hide */
- public void setIntentPersistableExtras(PersistableBundle intentPersistableExtras) {
- mIntentPersistableExtras = intentPersistableExtras;
- }
-
- /** @hide */
- public void setWeight(int weight) {
- mWeight = weight;
- }
-
- /** @hide */
- public void setExtras(PersistableBundle extras) {
- mExtras = extras;
+ public void setIconResourceId(int iconResourceId) {
+ mIconResourceId = iconResourceId;
}
/** @hide */
@@ -643,9 +727,10 @@
sb.append(", extras=");
sb.append(mExtras);
+ sb.append(", flags=");
+ sb.append(mFlags);
+
if (includeInternalData) {
- sb.append(", flags=");
- sb.append(mFlags);
sb.append(", iconRes=");
sb.append(mIconResourceId);
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 4c51d49..b247f65 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -239,6 +239,17 @@
}
}
+ /**
+ * Return the max width and height for icons, in pixels.
+ */
+ public int getIconMaxDimensions() {
+ try {
+ return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @hide injection point */
@VisibleForTesting
protected int injectMyUserId() {
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 8055dd9..918c763 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -22,6 +22,8 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.LauncherApps.ShortcutQuery;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
import java.util.List;
@@ -52,7 +54,13 @@
@NonNull List<String> shortcutIds, int userId);
public abstract Intent createShortcutIntent(@NonNull String callingPackage,
- @NonNull ShortcutInfo shortcut, int userId);
+ @NonNull String packageName, @NonNull String shortcutId, int userId);
public abstract void addListener(@NonNull ShortcutChangeListener listener);
+
+ public abstract int getShortcutIconResId(@NonNull String callingPackage,
+ @NonNull ShortcutInfo shortcut, int userId);
+
+ public abstract ParcelFileDescriptor getShortcutIconFd(@NonNull String callingPackage,
+ @NonNull ShortcutInfo shortcut, int userId);
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index b3c8e3b..04e64af 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -358,6 +358,8 @@
// TODO: factor out callback to be non-nested, then move setter to constructor
// For now, calling setRemoteDevice will fire initial
// onOpened/onUnconfigured callbacks.
+ // This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
+ // cameraUser dies during setup.
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index d58ad22..4add962 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2070,6 +2070,24 @@
*/
public static final int CONTROL_SCENE_MODE_FACE_PRIORITY_LOW_LIGHT = 19;
+ /**
+ * <p>Scene mode values within the range of
+ * <code>[DEVICE_CUSTOM_START, DEVICE_CUSTOM_END]</code> are reserved for device specific
+ * customized scene modes.</p>
+ * @see CaptureRequest#CONTROL_SCENE_MODE
+ * @hide
+ */
+ public static final int CONTROL_SCENE_MODE_DEVICE_CUSTOM_START = 100;
+
+ /**
+ * <p>Scene mode values within the range of
+ * <code>[DEVICE_CUSTOM_START, DEVICE_CUSTOM_END]</code> are reserved for device specific
+ * customized scene modes.</p>
+ * @see CaptureRequest#CONTROL_SCENE_MODE
+ * @hide
+ */
+ public static final int CONTROL_SCENE_MODE_DEVICE_CUSTOM_END = 127;
+
//
// Enumeration values for CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
//
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 00dd780..37d2ea2 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -63,7 +63,8 @@
/**
* HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
*/
-public class CameraDeviceImpl extends CameraDevice {
+public class CameraDeviceImpl extends CameraDevice
+ implements IBinder.DeathRecipient {
private final String TAG;
private final boolean DEBUG = false;
@@ -261,7 +262,14 @@
return mCallbacks;
}
- public void setRemoteDevice(ICameraDeviceUser remoteDevice) {
+ /**
+ * Set remote device, which triggers initial onOpened/onUnconfigured callbacks
+ *
+ * <p>This function may post onDisconnected and throw CAMERA_DISCONNECTED if remoteDevice dies
+ * during setup.</p>
+ *
+ */
+ public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
synchronized(mInterfaceLock) {
// TODO: Move from decorator to direct binder-mediated exceptions
// If setRemoteFailure already called, do nothing
@@ -269,6 +277,20 @@
mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
+ IBinder remoteDeviceBinder = remoteDevice.asBinder();
+ // For legacy camera device, remoteDevice is in the same process, and
+ // asBinder returns NULL.
+ if (remoteDeviceBinder != null) {
+ try {
+ remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
+ } catch (RemoteException e) {
+ CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
+
+ throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+ "The camera device has encountered a serious error");
+ }
+ }
+
mDeviceHandler.post(mCallOnOpened);
mDeviceHandler.post(mCallOnUnconfigured);
}
@@ -1962,4 +1984,28 @@
return mCharacteristics;
}
+ /**
+ * Listener for binder death.
+ *
+ * <p> Handle binder death for ICameraDeviceUser. Trigger onError.</p>
+ */
+ public void binderDied() {
+ Log.w(TAG, "CameraDevice " + mCameraId + " died unexpectedly");
+
+ if (mRemoteDevice == null) {
+ return; // Camera already closed
+ }
+
+ mInError = true;
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ if (!isClosed()) {
+ mDeviceCallback.onError(CameraDeviceImpl.this,
+ CameraDeviceCallbacks.ERROR_CAMERA_SERVICE);
+ }
+ }
+ };
+ CameraDeviceImpl.this.mDeviceHandler.post(r);
+ }
}
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index ba8bd34..95ffb44 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -19,6 +19,7 @@
import android.annotation.SystemApi;
import android.app.DownloadManager;
import android.app.backup.BackupManager;
+import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.RemoteException;
@@ -33,12 +34,16 @@
import java.net.SocketException;
/**
- * Class that provides network traffic statistics. These statistics include
+ * Class that provides network traffic statistics. These statistics include
* bytes transmitted and received and network packets transmitted and received,
* over all interfaces, over the mobile interface, and on a per-UID basis.
* <p>
- * These statistics may not be available on all platforms. If the statistics
- * are not supported by this device, {@link #UNSUPPORTED} will be returned.
+ * These statistics may not be available on all platforms. If the statistics are
+ * not supported by this device, {@link #UNSUPPORTED} will be returned.
+ * <p>
+ * Note that the statistics returned by this class reset and start from zero
+ * after every reboot. To access more robust historical network statistics data,
+ * use {@link NetworkStatsManager} instead.
*/
public class TrafficStats {
/**
@@ -497,14 +502,27 @@
* monotonically since device boot. Statistics are measured at the network
* layer, so they include both TCP and UDP usage.
* <p>
- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
- * {@link #UNSUPPORTED} on devices where statistics aren't available.
+ * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may
+ * return {@link #UNSUPPORTED} on devices where statistics aren't available.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
+ * report traffic statistics for the calling UID. It will return
+ * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
+ * historical network statistics belonging to other UIDs, use
+ * {@link NetworkStatsManager}.
*
* @see android.os.Process#myUid()
* @see android.content.pm.ApplicationInfo#uid
*/
public static long getUidTxBytes(int uid) {
- return nativeGetUidStat(uid, TYPE_TX_BYTES);
+ // This isn't actually enforcing any security; it just returns the
+ // unsupported value. The real filtering is done at the kernel level.
+ final int callingUid = android.os.Process.myUid();
+ if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
+ return nativeGetUidStat(uid, TYPE_TX_BYTES);
+ } else {
+ return UNSUPPORTED;
+ }
}
/**
@@ -515,12 +533,25 @@
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
* {@link #UNSUPPORTED} on devices where statistics aren't available.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
+ * report traffic statistics for the calling UID. It will return
+ * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
+ * historical network statistics belonging to other UIDs, use
+ * {@link NetworkStatsManager}.
*
* @see android.os.Process#myUid()
* @see android.content.pm.ApplicationInfo#uid
*/
public static long getUidRxBytes(int uid) {
- return nativeGetUidStat(uid, TYPE_RX_BYTES);
+ // This isn't actually enforcing any security; it just returns the
+ // unsupported value. The real filtering is done at the kernel level.
+ final int callingUid = android.os.Process.myUid();
+ if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
+ return nativeGetUidStat(uid, TYPE_RX_BYTES);
+ } else {
+ return UNSUPPORTED;
+ }
}
/**
@@ -531,12 +562,25 @@
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
* {@link #UNSUPPORTED} on devices where statistics aren't available.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
+ * report traffic statistics for the calling UID. It will return
+ * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
+ * historical network statistics belonging to other UIDs, use
+ * {@link NetworkStatsManager}.
*
* @see android.os.Process#myUid()
* @see android.content.pm.ApplicationInfo#uid
*/
public static long getUidTxPackets(int uid) {
- return nativeGetUidStat(uid, TYPE_TX_PACKETS);
+ // This isn't actually enforcing any security; it just returns the
+ // unsupported value. The real filtering is done at the kernel level.
+ final int callingUid = android.os.Process.myUid();
+ if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
+ return nativeGetUidStat(uid, TYPE_TX_PACKETS);
+ } else {
+ return UNSUPPORTED;
+ }
}
/**
@@ -547,12 +591,25 @@
* <p>
* Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return
* {@link #UNSUPPORTED} on devices where statistics aren't available.
+ * <p>
+ * Starting in {@link android.os.Build.VERSION_CODES#N} this will only
+ * report traffic statistics for the calling UID. It will return
+ * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access
+ * historical network statistics belonging to other UIDs, use
+ * {@link NetworkStatsManager}.
*
* @see android.os.Process#myUid()
* @see android.content.pm.ApplicationInfo#uid
*/
public static long getUidRxPackets(int uid) {
- return nativeGetUidStat(uid, TYPE_RX_PACKETS);
+ // This isn't actually enforcing any security; it just returns the
+ // unsupported value. The real filtering is done at the kernel level.
+ final int callingUid = android.os.Process.myUid();
+ if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) {
+ return nativeGetUidStat(uid, TYPE_RX_PACKETS);
+ } else {
+ return UNSUPPORTED;
+ }
}
/**
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8281279..e1c7ad77 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -465,6 +465,7 @@
};
public abstract long getProcessStateTime(int state, long elapsedRealtimeUs, int which);
+ public abstract Timer getProcessStateTimer(int state);
public abstract Timer getVibratorOnTimer();
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 0d94072..cb85eef 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -16,6 +16,9 @@
package android.os;
+import android.content.Context;
+import android.util.Log;
+
import com.android.internal.os.IDropBoxManagerService;
import java.io.ByteArrayInputStream;
@@ -40,6 +43,8 @@
*/
public class DropBoxManager {
private static final String TAG = "DropBoxManager";
+
+ private final Context mContext;
private final IDropBoxManagerService mService;
/** Flag value: Entry's content was deleted to save space. */
@@ -249,14 +254,20 @@
}
/** {@hide} */
- public DropBoxManager(IDropBoxManagerService service) { mService = service; }
+ public DropBoxManager(Context context, IDropBoxManagerService service) {
+ mContext = context;
+ mService = service;
+ }
/**
* Create a dummy instance for testing. All methods will fail unless
* overridden with an appropriate mock implementation. To obtain a
* functional instance, use {@link android.content.Context#getSystemService}.
*/
- protected DropBoxManager() { mService = null; }
+ protected DropBoxManager() {
+ mContext = null;
+ mService = null;
+ }
/**
* Stores human-readable text. The data may be discarded eventually (or even
@@ -270,6 +281,11 @@
try {
mService.add(new Entry(tag, 0, data));
} catch (RemoteException e) {
+ if (e instanceof TransactionTooLargeException
+ && mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+ Log.e(TAG, "App sent too much data, so it was ignored", e);
+ return;
+ }
throw e.rethrowFromSystemServer();
}
}
@@ -286,6 +302,11 @@
try {
mService.add(new Entry(tag, 0, data, flags));
} catch (RemoteException e) {
+ if (e instanceof TransactionTooLargeException
+ && mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+ Log.e(TAG, "App sent too much data, so it was ignored", e);
+ return;
+ }
throw e.rethrowFromSystemServer();
}
}
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index 838279b..082194b 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -25,10 +25,12 @@
void removePowerSaveWhitelistApp(String name);
String[] getSystemPowerWhitelistExceptIdle();
String[] getSystemPowerWhitelist();
+ String[] getUserPowerWhitelist();
String[] getFullPowerWhitelistExceptIdle();
String[] getFullPowerWhitelist();
int[] getAppIdWhitelistExceptIdle();
int[] getAppIdWhitelist();
+ int[] getAppIdUserWhitelist();
int[] getAppIdTempWhitelist();
boolean isPowerSaveWhitelistExceptIdleApp(String name);
boolean isPowerSaveWhitelistApp(String name);
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index f36bb29..5872f74 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -86,6 +86,8 @@
* @param b a Bundle to be copied.
*
* @throws IllegalArgumentException if any element of {@code b} cannot be persisted.
+ *
+ * @hide
*/
public PersistableBundle(Bundle b) {
this(b.getMap());
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 8fd3b0c..4506f51 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -998,6 +998,31 @@
throws IllegalArgumentException, SecurityException;
/**
+ * On some devices, the foreground process may have one or more CPU
+ * cores exclusively reserved for it. This method can be used to
+ * retrieve which cores that are (if any), so the calling process
+ * can then use sched_setaffinity() to lock a thread to these cores.
+ * Note that the calling process must currently be running in the
+ * foreground for this method to return any cores.
+ *
+ * The CPU core(s) exclusively reserved for the foreground process will
+ * stay reserved for as long as the process stays in the foreground.
+ *
+ * As soon as a process leaves the foreground, those CPU cores will
+ * no longer be reserved for it, and will most likely be reserved for
+ * the new foreground process. It's not necessary to change the affinity
+ * of your process when it leaves the foreground (if you had previously
+ * set it to use a reserved core); the OS will automatically take care
+ * of resetting the affinity at that point.
+ *
+ * @return an array of integers, indicating the CPU cores exclusively
+ * reserved for this process. The array will have length zero if no
+ * CPU cores are exclusively reserved for this process at this point
+ * in time.
+ */
+ public static final native int[] getExclusiveCores();
+
+ /**
* Set the priority of the calling thread, based on Linux priorities. See
* {@link #setThreadPriority(int, int)} for more information.
*
diff --git a/core/java/android/os/health/HealthKeys.java b/core/java/android/os/health/HealthKeys.java
new file mode 100644
index 0000000..842def3
--- /dev/null
+++ b/core/java/android/os/health/HealthKeys.java
@@ -0,0 +1,219 @@
+/*
+ * 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+/**
+ * Constants and stuff for the android.os.health package.
+ *
+ * @hide
+ */
+public class HealthKeys {
+
+ /**
+ * No valid key will ever be 0.
+ */
+ public static final int UNKNOWN_KEY = 0;
+
+ /*
+ * Base key for each of the different classes. There is
+ * nothing intrinsic to the operation of the value of the
+ * keys. It's just segmented for better debugging. The
+ * classes don't mix them anway.
+ */
+ public static final int BASE_UID = 10000;
+ public static final int BASE_PID = 20000;
+ public static final int BASE_PROCESS = 30000;
+ public static final int BASE_PACKAGE = 40000;
+ public static final int BASE_SERVICE = 50000;
+
+ /*
+ * The types of values supported by HealthStats.
+ */
+ public static final int TYPE_TIMER = 0;
+ public static final int TYPE_MEASUREMENT = 1;
+ public static final int TYPE_STATS = 2;
+ public static final int TYPE_TIMERS = 3;
+ public static final int TYPE_MEASUREMENTS = 4;
+
+ public static final int TYPE_COUNT = 5;
+
+ /**
+ * Annotation to mark public static final int fields that are to be used
+ * as field keys in HealthStats.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.FIELD})
+ public @interface Constant {
+ /**
+ * One of the TYPE_* constants above.
+ */
+ int type();
+ }
+
+ /**
+ * Class to gather the constants defined in a class full of constants and
+ * build the key indices used by HealthStatsWriter and HealthStats.
+ *
+ * @hide
+ */
+ public static class Constants {
+ private final String mDataType;
+ private final int[][] mKeys = new int[TYPE_COUNT][];
+
+ /**
+ * Pass in a class to gather the public static final int fields that are
+ * tagged with the @Constant annotation.
+ */
+ public Constants(Class clazz) {
+ // Save the class name for debugging
+ mDataType = clazz.getSimpleName();
+
+ // Iterate through the list of fields on this class, and build the
+ // constant arrays for these fields.
+ final Field[] fields = clazz.getDeclaredFields();
+ final Class<Constant> annotationClass = Constant.class;
+
+ final int N = fields.length;
+
+ final SortedIntArray[] keys = new SortedIntArray[mKeys.length];
+ for (int i=0; i<keys.length; i++) {
+ keys[i] = new SortedIntArray(N);
+ }
+
+ for (int i=0; i<N; i++) {
+ final Field field = fields[i];
+ final Constant constant = field.getAnnotation(annotationClass);
+ if (constant != null) {
+ final int type = constant.type();
+ if (type >= keys.length) {
+ throw new RuntimeException("Unknown Constant type " + type
+ + " on " + field);
+ }
+ try {
+ keys[type].addValue(field.getInt(null));
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException("Can't read constant value type=" + type
+ + " field=" + field, ex);
+ }
+ }
+ }
+
+ for (int i=0; i<keys.length; i++) {
+ mKeys[i] = keys[i].getArray();
+ }
+ }
+
+ /**
+ * Get a string representation of this class. Useful for debugging. It will be the
+ * simple name of the class passed in the constructor.
+ */
+ public String getDataType() {
+ return mDataType;
+ }
+
+ /**
+ * Return how many keys there are for the given field type.
+ *
+ * @see TYPE_TIMER
+ * @see TYPE_MEASUREMENT
+ * @see TYPE_TIMERS
+ * @see TYPE_MEASUREMENTS
+ * @see TYPE_STATS
+ */
+ public int getSize(int type) {
+ return mKeys[type].length;
+ }
+
+ /**
+ * Return the index for the given type and key combination in the array of field
+ * keys or values.
+ *
+ * @see TYPE_TIMER
+ * @see TYPE_MEASUREMENT
+ * @see TYPE_TIMERS
+ * @see TYPE_MEASUREMENTS
+ * @see TYPE_STATS
+ */
+ public int getIndex(int type, int key) {
+ final int index = Arrays.binarySearch(mKeys[type], key);
+ if (index >= 0) {
+ return index;
+ } else {
+ throw new RuntimeException("Unknown Constant " + key + " (of type "
+ + type + " )");
+ }
+ }
+
+ /**
+ * Get the array of keys for the given field type.
+ */
+ public int[] getKeys(int type) {
+ return mKeys[type];
+ }
+ }
+
+ /**
+ * An array of fixed size that will be sorted.
+ */
+ private static class SortedIntArray {
+ int mCount;
+ int[] mArray;
+
+ /**
+ * Construct with the maximum number of values.
+ */
+ SortedIntArray(int maxCount) {
+ mArray = new int[maxCount];
+ }
+
+ /**
+ * Add a value.
+ */
+ void addValue(int value) {
+ mArray[mCount++] = value;
+ }
+
+ /**
+ * Get the array of values that have been added, with the values in
+ * numerically increasing order.
+ */
+ int[] getArray() {
+ if (mCount == mArray.length) {
+ Arrays.sort(mArray);
+ return mArray;
+ } else {
+ final int[] result = new int[mCount];
+ System.arraycopy(mArray, 0, result, 0, mCount);
+ Arrays.sort(result);
+ return result;
+ }
+ }
+ }
+}
+
+
diff --git a/core/java/android/os/health/HealthStats.java b/core/java/android/os/health/HealthStats.java
new file mode 100644
index 0000000..f0489e2
--- /dev/null
+++ b/core/java/android/os/health/HealthStats.java
@@ -0,0 +1,481 @@
+/*
+ * 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * A HealthStats object contains system health data about an application.
+ *
+ * <p>
+ * <b>Data Types</b><br>
+ * Each of the keys references data in one of five data types:
+ *
+ * <p>
+ * A <b>measurement</b> metric contains a sinlge {@code long} value. That value may
+ * be a count, a time, or some other type of value. The unit for a measurement
+ * (COUNT, MS, etc) will always be in the name of the constant for the key to
+ * retrieve it. For example, the
+ * {@link android.os.health.UidHealthStats#MEASUREMENT_WIFI_TX_MS UidHealthStats.MEASUREMENT_WIFI_TX_MS}
+ * value is the number of milliseconds (ms) that were spent transmitting on wifi by an
+ * application. The
+ * {@link android.os.health.UidHealthStats#MEASUREMENT_MOBILE_RX_PACKETS UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS}
+ * measurement is the number of packets received on behalf of an application.
+ * The {@link android.os.health.UidHealthStats#MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT
+ * UidHealthStats.MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT}
+ * measurement is the number of times the user touched the screen, causing the
+ * screen to stay awake.
+ *
+ *
+ * <p>
+ * A <b>timer</b> metric contains an {@code int} count and a {@code long} time,
+ * measured in milliseconds. Timers track how many times a resource was used, and
+ * the total duration for that usage. For example, the
+ * {@link android.os.health.UidHealthStats#TIMER_FLASHLIGHT}
+ * timer tracks how many times the application turned on the flashlight, and for
+ * how many milliseconds total it kept it on.
+ *
+ * <p>
+ * A <b>measurement map</b> metric is a mapping of {@link java.lang.String} names to
+ * {@link java.lang.Long} values. The names typically are application provided names. For
+ * example, the
+ * {@link android.os.health.PackageHealthStats#MEASUREMENTS_WAKEUP_ALARMS_COUNT
+ * PackageHealthStats.MEASUREMENTS_WAKEUP_ALARMS_COUNT}
+ * measurement map is a mapping of the tag provided to the
+ * {@link android.app.AlarmManager} when the alarm is scheduled.
+ *
+ * <p>
+ * A <b>timer map</b> metric is a mapping of {@link java.lang.String} names to
+ * {@link android.os.health.TimerStat} objects. The names are typically application
+ * provided names. For example, the
+ * {@link android.os.health.UidHealthStats#TIMERS_WAKELOCKS_PARTIAL UidHealthStats.TIMERS_WAKELOCKS_PARTIAL}
+ * is a mapping of tag provided to the {@link android.os.PowerManager} when the
+ * wakelock is created to the number of times and for how long each wakelock was
+ * active.
+ *
+ * <p>
+ * Lastly, a <b>health stats</b> metric is a mapping of {@link java.lang.String}
+ * names to a recursive {@link android.os.health.HealthStats} object containing
+ * more detailed information. For example, the
+ * {@link android.os.health.UidHealthStats#STATS_PACKAGES UidHealthStats.STATS_PACKAGES}
+ * metric is a mapping of the package names for each of the APKs sharing a uid to
+ * the information recorded for that apk. The returned HealthStats objects will
+ * each be associated with a different set of constants. For the HealthStats
+ * returned for UidHealthStats.STATS_PACKAGES, the keys come from the
+ * {@link android.os.health.PackageHealthStats} class.
+ *
+ */
+public class HealthStats {
+ // Header fields
+ private String mDataType;
+
+ // TimerStat fields
+ private int[] mTimerKeys;
+ private int[] mTimerCounts;
+ private long[] mTimerTimes;
+
+ // Measurement fields
+ private int[] mMeasurementKeys;
+ private long[] mMeasurementValues;
+
+ // Stats fields
+ private int[] mStatsKeys;
+ private ArrayMap<String,HealthStats>[] mStatsValues;
+
+ // Timers fields
+ private int[] mTimersKeys;
+ private ArrayMap<String,TimerStat>[] mTimersValues;
+
+ // Measurements fields
+ private int[] mMeasurementsKeys;
+ private ArrayMap<String,Long>[] mMeasurementsValues;
+
+ /**
+ * HealthStats empty constructor not implemented because this
+ * class is read-only.
+ */
+ private HealthStats() {
+ throw new RuntimeException("unsupported");
+ }
+
+ /**
+ * Construct a health stats object from a parcel.
+ *
+ * @hide
+ */
+ public HealthStats(Parcel in) {
+ int count;
+
+ // Header fields
+ mDataType = in.readString();
+
+ // TimerStat fields
+ count = in.readInt();
+ mTimerKeys = new int[count];
+ mTimerCounts = new int[count];
+ mTimerTimes = new long[count];
+ for (int i=0; i<count; i++) {
+ mTimerKeys[i] = in.readInt();
+ mTimerCounts[i] = in.readInt();
+ mTimerTimes[i] = in.readLong();
+ }
+
+ // Measurement fields
+ count = in.readInt();
+ mMeasurementKeys = new int[count];
+ mMeasurementValues = new long[count];
+ for (int i=0; i<count; i++) {
+ mMeasurementKeys[i] = in.readInt();
+ mMeasurementValues[i] = in.readLong();
+ }
+
+ // Stats fields
+ count = in.readInt();
+ mStatsKeys = new int[count];
+ mStatsValues = new ArrayMap[count];
+ for (int i=0; i<count; i++) {
+ mStatsKeys[i] = in.readInt();
+ mStatsValues[i] = createHealthStatsMap(in);
+ }
+
+ // Timers fields
+ count = in.readInt();
+ mTimersKeys = new int[count];
+ mTimersValues = new ArrayMap[count];
+ for (int i=0; i<count; i++) {
+ mTimersKeys[i] = in.readInt();
+ mTimersValues[i] = createParcelableMap(in, TimerStat.CREATOR);
+ }
+
+ // Measurements fields
+ count = in.readInt();
+ mMeasurementsKeys = new int[count];
+ mMeasurementsValues = new ArrayMap[count];
+ for (int i=0; i<count; i++) {
+ mMeasurementsKeys[i] = in.readInt();
+ mMeasurementsValues[i] = createLongsMap(in);
+ }
+ }
+
+ /**
+ * Get a name representing the contents of this object.
+ *
+ * @see UidHealthStats
+ * @see PackageHealthStats
+ * @see PidHealthStats
+ * @see ProcessHealthStats
+ * @see ServiceHealthStats
+ */
+ public String getDataType() {
+ return mDataType;
+ }
+
+ /**
+ * Return whether this object contains a TimerStat for the supplied key.
+ */
+ public boolean hasTimer(int key) {
+ return getIndex(mTimerKeys, key) >= 0;
+ }
+
+ /**
+ * Return a TimerStat object for the given key.
+ *
+ * This will allocate a new {@link TimerStat} object, which may be wasteful. Instead, use
+ * {@link #getTimerCount} and {@link #getTimerTime}.
+ *
+ * @throws IndexOutOfBoundsException When the key is not present in this object.
+ * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
+ */
+ public TimerStat getTimer(int key) {
+ final int index = getIndex(mTimerKeys, key);
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType
+ + " key=" + key);
+ }
+ return new TimerStat(mTimerCounts[index], mTimerTimes[index]);
+ }
+
+ /**
+ * Get the count for the timer for the given key.
+ *
+ * @throws IndexOutOfBoundsException When the key is not present in this object.
+ * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
+ */
+ public int getTimerCount(int key) {
+ final int index = getIndex(mTimerKeys, key);
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType
+ + " key=" + key);
+ }
+ return mTimerCounts[index];
+ }
+
+ /**
+ * Get the time for the timer for the given key, in milliseconds.
+ *
+ * @throws IndexOutOfBoundsException When the key is not present in this object.
+ * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
+ */
+ public long getTimerTime(int key) {
+ final int index = getIndex(mTimerKeys, key);
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType
+ + " key=" + key);
+ }
+ return mTimerTimes[index];
+ }
+
+ /**
+ * Get the number of timer values in this object. Can be used to iterate through
+ * the available timers.
+ *
+ * @see #getTimerKeyAt
+ */
+ public int getTimerKeyCount() {
+ return mTimerKeys.length;
+ }
+
+ /**
+ * Get the key for the timer at the given index. Index must be between 0 and the result
+ * of {@link #getTimerKeyCount getTimerKeyCount()}.
+ *
+ * @see #getTimerKeyCount
+ */
+ public int getTimerKeyAt(int index) {
+ return mTimerKeys[index];
+ }
+
+ /**
+ * Return whether this object contains a measurement for the supplied key.
+ */
+ public boolean hasMeasurement(int key) {
+ return getIndex(mMeasurementKeys, key) >= 0;
+ }
+
+ /**
+ * Get the measurement for the given key.
+ *
+ * @throws IndexOutOfBoundsException When the key is not present in this object.
+ * @see #hasMeasurement hasMeasurement(int) To check if a value for the given key is present.
+ */
+ public long getMeasurement(int key) {
+ final int index = getIndex(mMeasurementKeys, key);
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Bad measurement key dataType=" + mDataType
+ + " key=" + key);
+ }
+ return mMeasurementValues[index];
+ }
+
+ /**
+ * Get the number of measurement values in this object. Can be used to iterate through
+ * the available measurements.
+ *
+ * @see #getMeasurementKeyAt
+ */
+ public int getMeasurementKeyCount() {
+ return mMeasurementKeys.length;
+ }
+
+ /**
+ * Get the key for the measurement at the given index. Index must be between 0 and the result
+ * of {@link #getMeasurementKeyCount getMeasurementKeyCount()}.
+ *
+ * @see #getMeasurementKeyCount
+ */
+ public int getMeasurementKeyAt(int index) {
+ return mMeasurementKeys[index];
+ }
+
+ /**
+ * Return whether this object contains a HealthStats map for the supplied key.
+ */
+ public boolean hasStats(int key) {
+ return getIndex(mStatsKeys, key) >= 0;
+ }
+
+ /**
+ * Get the HealthStats map for the given key.
+ *
+ * @throws IndexOutOfBoundsException When the key is not present in this object.
+ * @see #hasStats hasStats(int) To check if a value for the given key is present.
+ */
+ public Map<String,HealthStats> getStats(int key) {
+ final int index = getIndex(mStatsKeys, key);
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Bad stats key dataType=" + mDataType
+ + " key=" + key);
+ }
+ return mStatsValues[index];
+ }
+
+ /**
+ * Get the number of HealthStat map values in this object. Can be used to iterate through
+ * the available measurements.
+ *
+ * @see #getMeasurementKeyAt
+ */
+ public int getStatsKeyCount() {
+ return mStatsKeys.length;
+ }
+
+ /**
+ * Get the key for the timer at the given index. Index must be between 0 and the result
+ * of {@link #getStatsKeyCount getStatsKeyCount()}.
+ *
+ * @see #getStatsKeyCount
+ */
+ public int getStatsKeyAt(int index) {
+ return mStatsKeys[index];
+ }
+
+ /**
+ * Return whether this object contains a timers map for the supplied key.
+ */
+ public boolean hasTimers(int key) {
+ return getIndex(mTimersKeys, key) >= 0;
+ }
+
+ /**
+ * Get the TimerStat map for the given key.
+ *
+ * @throws IndexOutOfBoundsException When the key is not present in this object.
+ * @see #hasTimers hasTimers(int) To check if a value for the given key is present.
+ */
+ public Map<String,TimerStat> getTimers(int key) {
+ final int index = getIndex(mTimersKeys, key);
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Bad timers key dataType=" + mDataType
+ + " key=" + key);
+ }
+ return mTimersValues[index];
+ }
+
+ /**
+ * Get the number of timer map values in this object. Can be used to iterate through
+ * the available timer maps.
+ *
+ * @see #getTimersKeyAt
+ */
+ public int getTimersKeyCount() {
+ return mTimersKeys.length;
+ }
+
+ /**
+ * Get the key for the timer map at the given index. Index must be between 0 and the result
+ * of {@link #getTimersKeyCount getTimersKeyCount()}.
+ *
+ * @see #getTimersKeyCount
+ */
+ public int getTimersKeyAt(int index) {
+ return mTimersKeys[index];
+ }
+
+ /**
+ * Return whether this object contains a measurements map for the supplied key.
+ */
+ public boolean hasMeasurements(int key) {
+ return getIndex(mMeasurementsKeys, key) >= 0;
+ }
+
+ /**
+ * Get the measurements map for the given key.
+ *
+ * @throws IndexOutOfBoundsException When the key is not present in this object.
+ * @see #hasMeasurements To check if a value for the given key is present.
+ */
+ public Map<String,Long> getMeasurements(int key) {
+ final int index = getIndex(mMeasurementsKeys, key);
+ if (index < 0) {
+ throw new IndexOutOfBoundsException("Bad measurements key dataType=" + mDataType
+ + " key=" + key);
+ }
+ return mMeasurementsValues[index];
+ }
+
+ /**
+ * Get the number of measurement map values in this object. Can be used to iterate through
+ * the available measurement maps.
+ *
+ * @see #getMeasurementsKeyAt
+ */
+ public int getMeasurementsKeyCount() {
+ return mMeasurementsKeys.length;
+ }
+
+ /**
+ * Get the key for the measurement map at the given index.
+ * Index must be between 0 and the result
+ * of {@link #getMeasurementsKeyCount getMeasurementsKeyCount()}.
+ *
+ * @see #getMeasurementsKeyCount
+ */
+ public int getMeasurementsKeyAt(int index) {
+ return mMeasurementsKeys[index];
+ }
+
+ /**
+ * Get the index in keys of key.
+ */
+ private static int getIndex(int[] keys, int key) {
+ return Arrays.binarySearch(keys, key);
+ }
+
+ /**
+ * Create an ArrayMap<String,HealthStats> from the given Parcel.
+ */
+ private static ArrayMap<String,HealthStats> createHealthStatsMap(Parcel in) {
+ final int count = in.readInt();
+ final ArrayMap<String,HealthStats> result = new ArrayMap<String,HealthStats>(count);
+ for (int i=0; i<count; i++) {
+ result.put(in.readString(), new HealthStats(in));
+ }
+ return result;
+ }
+
+ /**
+ * Create an ArrayMap<String,T extends Parcelable> from the given Parcel using
+ * the given Parcelable.Creator.
+ */
+ private static <T extends Parcelable> ArrayMap<String,T> createParcelableMap(Parcel in,
+ Parcelable.Creator<T> creator) {
+ final int count = in.readInt();
+ final ArrayMap<String,T> result = new ArrayMap<String,T>(count);
+ for (int i=0; i<count; i++) {
+ result.put(in.readString(), creator.createFromParcel(in));
+ }
+ return result;
+ }
+
+ /**
+ * Create an ArrayMap<String,Long> from the given Parcel.
+ */
+ private static ArrayMap<String,Long> createLongsMap(Parcel in) {
+ final int count = in.readInt();
+ final ArrayMap<String,Long> result = new ArrayMap<String,Long>(count);
+ for (int i=0; i<count; i++) {
+ result.put(in.readString(), in.readLong());
+ }
+ return result;
+ }
+}
+
diff --git a/core/java/android/os/health/HealthStatsParceler.aidl b/core/java/android/os/health/HealthStatsParceler.aidl
new file mode 100644
index 0000000..68c348b
--- /dev/null
+++ b/core/java/android/os/health/HealthStatsParceler.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 android.os.health;
+
+parcelable HealthStatsParceler;
diff --git a/core/java/android/os/health/HealthStatsParceler.java b/core/java/android/os/health/HealthStatsParceler.java
new file mode 100644
index 0000000..28b3694
--- /dev/null
+++ b/core/java/android/os/health/HealthStatsParceler.java
@@ -0,0 +1,87 @@
+/*
+ * 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Class to allow sending the HealthStats through aidl generated glue.
+ *
+ * The alternative would be to send a HealthStats object, which would
+ * require constructing one, and then immediately flattening it. This
+ * saves that step at the cost of doing the extra flattening when
+ * accessed in the same process as the writer.
+ *
+ * The HealthStatsWriter passed in the constructor is retained, so don't
+ * reuse them.
+ * @hide
+ */
+public class HealthStatsParceler implements Parcelable {
+ private HealthStatsWriter mWriter;
+ private HealthStats mHealthStats;
+
+ public static final Parcelable.Creator<HealthStatsParceler> CREATOR
+ = new Parcelable.Creator<HealthStatsParceler>() {
+ public HealthStatsParceler createFromParcel(Parcel in) {
+ return new HealthStatsParceler(in);
+ }
+
+ public HealthStatsParceler[] newArray(int size) {
+ return new HealthStatsParceler[size];
+ }
+ };
+
+ public HealthStatsParceler(HealthStatsWriter writer) {
+ mWriter = writer;
+ }
+
+ public HealthStatsParceler(Parcel in) {
+ mHealthStats = new HealthStats(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ // See comment on mWriter declaration above.
+ if (mWriter != null) {
+ mWriter.flattenToParcel(out);
+ } else {
+ throw new RuntimeException("Can not re-parcel HealthStatsParceler that was"
+ + " constructed from a Parcel");
+ }
+ }
+
+ public HealthStats getHealthStats() {
+ if (mWriter != null) {
+ final Parcel parcel = Parcel.obtain();
+ mWriter.flattenToParcel(parcel);
+ parcel.setDataPosition(0);
+ mHealthStats = new HealthStats(parcel);
+ parcel.recycle();
+ }
+
+ return mHealthStats;
+ }
+}
+
diff --git a/core/java/android/os/health/HealthStatsWriter.java b/core/java/android/os/health/HealthStatsWriter.java
new file mode 100644
index 0000000..351836b
--- /dev/null
+++ b/core/java/android/os/health/HealthStatsWriter.java
@@ -0,0 +1,288 @@
+/*
+ * 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Class to write the health stats data into a parcel, so it can then be
+ * retrieved via a {@link HealthStats} object.
+ *
+ * There is an attempt to keep this class as low overhead as possible, for
+ * example storing an int[] and a long[] instead of a TimerStat[].
+ *
+ * @hide
+ */
+public class HealthStatsWriter {
+ private final HealthKeys.Constants mConstants;
+
+ // TimerStat fields
+ private final boolean[] mTimerFields;
+ private final int[] mTimerCounts;
+ private final long[] mTimerTimes;
+
+ // Measurement fields
+ private final boolean[] mMeasurementFields;
+ private final long[] mMeasurementValues;
+
+ // Stats fields
+ private final ArrayMap<String,HealthStatsWriter>[] mStatsValues;
+
+ // Timers fields
+ private final ArrayMap<String,TimerStat>[] mTimersValues;
+
+ // Measurements fields
+ private final ArrayMap<String,Long>[] mMeasurementsValues;
+
+ /**
+ * Construct a HealthStatsWriter object with the given constants.
+ *
+ * The "getDataType()" of the resulting HealthStats object will be the
+ * short name of the java class that the Constants object was initalized
+ * with.
+ */
+ public HealthStatsWriter(HealthKeys.Constants constants) {
+ mConstants = constants;
+
+ // TimerStat
+ final int timerCount = constants.getSize(HealthKeys.TYPE_TIMER);
+ mTimerFields = new boolean[timerCount];
+ mTimerCounts = new int[timerCount];
+ mTimerTimes = new long[timerCount];
+
+ // Measurement
+ final int measurementCount = constants.getSize(HealthKeys.TYPE_MEASUREMENT);
+ mMeasurementFields = new boolean[measurementCount];
+ mMeasurementValues = new long[measurementCount];
+
+ // Stats
+ final int statsCount = constants.getSize(HealthKeys.TYPE_STATS);
+ mStatsValues = new ArrayMap[statsCount];
+
+ // Timers
+ final int timersCount = constants.getSize(HealthKeys.TYPE_TIMERS);
+ mTimersValues = new ArrayMap[timersCount];
+
+ // Measurements
+ final int measurementsCount = constants.getSize(HealthKeys.TYPE_MEASUREMENTS);
+ mMeasurementsValues = new ArrayMap[measurementsCount];
+ }
+
+ /**
+ * Add a timer for the given key.
+ */
+ public void addTimer(int timerId, int count, long time) {
+ final int index = mConstants.getIndex(HealthKeys.TYPE_TIMER, timerId);
+
+ mTimerFields[index] = true;
+ mTimerCounts[index] = count;
+ mTimerTimes[index] = time;
+ }
+
+ /**
+ * Add a measurement for the given key.
+ */
+ public void addMeasurement(int measurementId, long value) {
+ final int index = mConstants.getIndex(HealthKeys.TYPE_MEASUREMENT, measurementId);
+
+ mMeasurementFields[index] = true;
+ mMeasurementValues[index] = value;
+ }
+
+ /**
+ * Add a recursive HealthStats object for the given key and string name. The value
+ * is stored as a HealthStatsWriter until this object is written to a parcel, so
+ * don't attempt to reuse the HealthStatsWriter.
+ *
+ * The value field should not be null.
+ */
+ public void addStats(int key, String name, HealthStatsWriter value) {
+ final int index = mConstants.getIndex(HealthKeys.TYPE_STATS, key);
+
+ ArrayMap<String,HealthStatsWriter> map = mStatsValues[index];
+ if (map == null) {
+ map = mStatsValues[index] = new ArrayMap<String,HealthStatsWriter>(1);
+ }
+ map.put(name, value);
+ }
+
+ /**
+ * Add a TimerStat for the given key and string name.
+ *
+ * The value field should not be null.
+ */
+ public void addTimers(int key, String name, TimerStat value) {
+ final int index = mConstants.getIndex(HealthKeys.TYPE_TIMERS, key);
+
+ ArrayMap<String,TimerStat> map = mTimersValues[index];
+ if (map == null) {
+ map = mTimersValues[index] = new ArrayMap<String,TimerStat>(1);
+ }
+ map.put(name, value);
+ }
+
+ /**
+ * Add a measurement for the given key and string name.
+ */
+ public void addMeasurements(int key, String name, long value) {
+ final int index = mConstants.getIndex(HealthKeys.TYPE_MEASUREMENTS, key);
+
+ ArrayMap<String,Long> map = mMeasurementsValues[index];
+ if (map == null) {
+ map = mMeasurementsValues[index] = new ArrayMap<String,Long>(1);
+ }
+ map.put(name, value);
+ }
+
+ /**
+ * Flattens the data in this HealthStatsWriter to the Parcel format
+ * that can be unparceled into a HealthStat.
+ * @more
+ * (Called flattenToParcel because this HealthStatsWriter itself is
+ * not parcelable and we don't flatten all the business about the
+ * HealthKeys.Constants, only the values that were actually supplied)
+ */
+ public void flattenToParcel(Parcel out) {
+ int[] keys;
+
+ // Header fields
+ out.writeString(mConstants.getDataType());
+
+ // TimerStat fields
+ out.writeInt(countBooleanArray(mTimerFields));
+ keys = mConstants.getKeys(HealthKeys.TYPE_TIMER);
+ for (int i=0; i<keys.length; i++) {
+ if (mTimerFields[i]) {
+ out.writeInt(keys[i]);
+ out.writeInt(mTimerCounts[i]);
+ out.writeLong(mTimerTimes[i]);
+ }
+ }
+
+ // Measurement fields
+ out.writeInt(countBooleanArray(mMeasurementFields));
+ keys = mConstants.getKeys(HealthKeys.TYPE_MEASUREMENT);
+ for (int i=0; i<keys.length; i++) {
+ if (mMeasurementFields[i]) {
+ out.writeInt(keys[i]);
+ out.writeLong(mMeasurementValues[i]);
+ }
+ }
+
+ // Stats
+ out.writeInt(countObjectArray(mStatsValues));
+ keys = mConstants.getKeys(HealthKeys.TYPE_STATS);
+ for (int i=0; i<keys.length; i++) {
+ if (mStatsValues[i] != null) {
+ out.writeInt(keys[i]);
+ writeHealthStatsWriterMap(out, mStatsValues[i]);
+ }
+ }
+
+ // Timers
+ out.writeInt(countObjectArray(mTimersValues));
+ keys = mConstants.getKeys(HealthKeys.TYPE_TIMERS);
+ for (int i=0; i<keys.length; i++) {
+ if (mTimersValues[i] != null) {
+ out.writeInt(keys[i]);
+ writeParcelableMap(out, mTimersValues[i]);
+ }
+ }
+
+ // Measurements
+ out.writeInt(countObjectArray(mMeasurementsValues));
+ keys = mConstants.getKeys(HealthKeys.TYPE_MEASUREMENTS);
+ for (int i=0; i<keys.length; i++) {
+ if (mMeasurementsValues[i] != null) {
+ out.writeInt(keys[i]);
+ writeLongsMap(out, mMeasurementsValues[i]);
+ }
+ }
+ }
+
+ /**
+ * Count how many of the fields have been set.
+ */
+ private static int countBooleanArray(boolean[] fields) {
+ int count = 0;
+ final int N = fields.length;
+ for (int i=0; i<N; i++) {
+ if (fields[i]) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Count how many of the fields have been set.
+ */
+ private static <T extends Object> int countObjectArray(T[] fields) {
+ int count = 0;
+ final int N = fields.length;
+ for (int i=0; i<N; i++) {
+ if (fields[i] != null) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Write a map of String to HealthStatsWriter to the Parcel.
+ */
+ private static void writeHealthStatsWriterMap(Parcel out,
+ ArrayMap<String,HealthStatsWriter> map) {
+ final int N = map.size();
+ out.writeInt(N);
+ for (int i=0; i<N; i++) {
+ out.writeString(map.keyAt(i));
+ map.valueAt(i).flattenToParcel(out);
+ }
+ }
+
+ /**
+ * Write a map of String to Parcelables to the Parcel.
+ */
+ private static <T extends Parcelable> void writeParcelableMap(Parcel out,
+ ArrayMap<String,T> map) {
+ final int N = map.size();
+ out.writeInt(N);
+ for (int i=0; i<N; i++) {
+ out.writeString(map.keyAt(i));
+ map.valueAt(i).writeToParcel(out, 0);
+ }
+ }
+
+ /**
+ * Write a map of String to Longs to the Parcel.
+ */
+ private static void writeLongsMap(Parcel out, ArrayMap<String,Long> map) {
+ final int N = map.size();
+ out.writeInt(N);
+ for (int i=0; i<N; i++) {
+ out.writeString(map.keyAt(i));
+ out.writeLong(map.valueAt(i));
+ }
+ }
+}
+
+
diff --git a/core/java/android/os/health/PackageHealthStats.java b/core/java/android/os/health/PackageHealthStats.java
new file mode 100644
index 0000000..2c30d5f
--- /dev/null
+++ b/core/java/android/os/health/PackageHealthStats.java
@@ -0,0 +1,50 @@
+/*
+ * 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link HealthStats#getStats(int) HealthStats.getStats(int)} with the
+ * {@link UidHealthStats#STATS_PACKAGES UidHealthStats.STATS_PACKAGES} key.
+ */
+public final class PackageHealthStats {
+
+ private PackageHealthStats() {
+ }
+
+ /**
+ * Key for a HealthStats with {@link ServiceHealthStats} keys for each of the
+ * services defined in this apk.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_STATS)
+ public static final int STATS_SERVICES = HealthKeys.BASE_PACKAGE + 1;
+
+ /**
+ * Key for a map of the number of times that a package's wakeup alarms have fired
+ * while the device was on battery.
+ *
+ * @see android.app.AlarmManager.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENTS)
+ public static final int MEASUREMENTS_WAKEUP_ALARMS_COUNT = HealthKeys.BASE_PACKAGE + 2;
+
+ /**
+ * @hide
+ */
+ public static final HealthKeys.Constants CONSTANTS
+ = new HealthKeys.Constants(PackageHealthStats.class);
+}
diff --git a/core/java/android/os/health/PidHealthStats.java b/core/java/android/os/health/PidHealthStats.java
new file mode 100644
index 0000000..fe3c02c
--- /dev/null
+++ b/core/java/android/os/health/PidHealthStats.java
@@ -0,0 +1,42 @@
+/*
+ * 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link HealthStats#getStats(int) HealthStats.getStats(int)} with the
+ * {@link UidHealthStats#STATS_PIDS UidHealthStats.STATS_PIDS} key.
+ */
+public final class PidHealthStats {
+
+ private PidHealthStats() {
+ }
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WAKE_NESTING_COUNT = HealthKeys.BASE_PID + 1;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WAKE_SUM_MS = HealthKeys.BASE_PID + 2;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WAKE_START_MS = HealthKeys.BASE_PID + 3;
+
+ /**
+ * @hide
+ */
+ public static final HealthKeys.Constants CONSTANTS = new HealthKeys.Constants(PidHealthStats.class);
+}
diff --git a/core/java/android/os/health/ProcessHealthStats.java b/core/java/android/os/health/ProcessHealthStats.java
new file mode 100644
index 0000000..e004ecb
--- /dev/null
+++ b/core/java/android/os/health/ProcessHealthStats.java
@@ -0,0 +1,51 @@
+/*
+ * 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link HealthStats#getStats(int) HealthStats.getStats(int)} with the
+ * {@link UidHealthStats#STATS_PROCESSES UidHealthStats.STATS_PROCESSES} key.
+ */
+public final class ProcessHealthStats {
+
+ private ProcessHealthStats() {
+ }
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_USER_TIME_MS = HealthKeys.BASE_PROCESS + 1;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_SYSTEM_TIME_MS = HealthKeys.BASE_PROCESS + 2;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_STARTS_COUNT = HealthKeys.BASE_PROCESS + 3;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_CRASHES_COUNT = HealthKeys.BASE_PROCESS + 4;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_ANR_COUNT = HealthKeys.BASE_PROCESS + 5;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_FOREGROUND_MS = HealthKeys.BASE_PROCESS + 6;
+
+ /**
+ * @hide
+ */
+ public static final HealthKeys.Constants CONSTANTS = new HealthKeys.Constants(ProcessHealthStats.class);
+}
diff --git a/core/java/android/os/health/ServiceHealthStats.java b/core/java/android/os/health/ServiceHealthStats.java
new file mode 100644
index 0000000..802ad31
--- /dev/null
+++ b/core/java/android/os/health/ServiceHealthStats.java
@@ -0,0 +1,40 @@
+/*
+ * 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link HealthStats#getStats(int) HealthStats.getStats(int)} with the
+ * {@link PackageHealthStats#STATS_SERVICES PackageHealthStats.STATS_SERVICES} key.
+ */
+public final class ServiceHealthStats {
+
+ private ServiceHealthStats() {
+ }
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_START_SERVICE_COUNT = HealthKeys.BASE_SERVICE + 1;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_LAUNCH_COUNT = HealthKeys.BASE_SERVICE + 2;
+
+ /**
+ * @hide
+ */
+ public static final HealthKeys.Constants CONSTANTS
+ = new HealthKeys.Constants(ServiceHealthStats.class);
+}
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
new file mode 100644
index 0000000..520e84e
--- /dev/null
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -0,0 +1,121 @@
+/*
+ * 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.health;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.app.IBatteryStats;
+
+/**
+ * Provides access to data about how various system resources are used by applications.
+ * @more
+ * <b>Battery Usage</b><br>
+ * The statistics related to power (battery) usage are recorded since the device
+ * was last unplugged. It is expected that applications schedule more work to do
+ * while the device is plugged in (e.g. using {@link android.app.job.JobScheduler
+ * JobScheduler}), and while that can affect charging rates, it is still preferable
+ * to actually draining the battery.
+ */
+public class SystemHealthManager {
+ private final IBatteryStats mBatteryStats;
+
+ /**
+ * Construct a new SystemHealthManager object.
+ * @hide
+ */
+ public SystemHealthManager() {
+ mBatteryStats = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME));
+ }
+
+ /**
+ * Obtain a SystemHealthManager object for the supplied context.
+ */
+ public static SystemHealthManager from(Context context) {
+ return (SystemHealthManager)context.getSystemService(Context.SYSTEM_HEALTH_SERVICE);
+ }
+
+ /**
+ * Return a {@link HealthStats} object containing a snapshot of system health
+ * metrics for the given uid (user-id, which in usually corresponds to application).
+ * @more
+ *
+ * An application must hold the {@link android.Manifest.permission#BATTERY_STATS
+ * android.permission.BATTERY_STATS} permission in order to retrieve any HealthStats
+ * other than its own.
+ *
+ * @param uid User ID for a given application.
+ * @return A {@link HealthStats} object containing the metrics for the requested
+ * application. The keys for this HealthStats object will be from the {@link UidHealthStats}
+ * class.
+ * @see Process#myUid()
+ */
+ public HealthStats takeUidSnapshot(int uid) {
+ try {
+ final HealthStatsParceler parceler = mBatteryStats.takeUidSnapshot(uid);
+ return parceler.getHealthStats();
+ } catch (RemoteException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ * Return a {@link HealthStats} object containing a snapshot of system health
+ * metrics for the application calling this API. This method is the same as calling
+ * {@code takeUidSnapshot(Process.myUid())}.
+ *
+ * @return A {@link HealthStats} object containing the metrics for this application. The keys
+ * for this HealthStats object will be from the {@link UidHealthStats} class.
+ */
+ public HealthStats takeMyUidSnapshot() {
+ return takeUidSnapshot(Process.myUid());
+ }
+
+ /**
+ * Return a {@link HealthStats} object containing a snapshot of system health
+ * metrics for the given uids (user-id, which in usually corresponds to application).
+ * @more
+ *
+ * An application must hold the {@link android.Manifest.permission#BATTERY_STATS
+ * android.permission.BATTERY_STATS} permission in order to retrieve any HealthStats
+ * other than its own.
+ *
+ * @param uids An array of User IDs to retrieve.
+ * @return An array of {@link HealthStats} objects containing the metrics for each of
+ * the requested uids. The keys for this HealthStats object will be from the
+ * {@link UidHealthStats} class.
+ */
+ public HealthStats[] takeUidSnapshots(int[] uids) {
+ try {
+ final HealthStatsParceler[] parcelers = mBatteryStats.takeUidSnapshots(uids);
+ final HealthStats[] results = new HealthStats[uids.length];
+ final int N = uids.length;
+ for (int i=0; i<N; i++) {
+ results[i] = parcelers[i].getHealthStats();
+ }
+ return results;
+ } catch (RemoteException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+}
+
diff --git a/core/java/android/os/health/TimerStat.java b/core/java/android/os/health/TimerStat.java
new file mode 100644
index 0000000..fc51b60
--- /dev/null
+++ b/core/java/android/os/health/TimerStat.java
@@ -0,0 +1,116 @@
+/*
+ * 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.health;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A TimerStat object stores a count and a time.
+ *
+ * @more
+ * When possible, the other APIs in this package avoid requiring a TimerStat
+ * object to be constructed, even internally, but the getTimers method on
+ * {@link android.os.health.HealthStats} does require TimerStat objects.
+ */
+public class TimerStat implements Parcelable {
+ private int mCount;
+ private long mTime;
+
+ /**
+ * The CREATOR instance for use by aidl Binder interfaces.
+ */
+ public static final Parcelable.Creator<TimerStat> CREATOR
+ = new Parcelable.Creator<TimerStat>() {
+ public TimerStat createFromParcel(Parcel in) {
+ return new TimerStat(in);
+ }
+
+ public TimerStat[] newArray(int size) {
+ return new TimerStat[size];
+ }
+ };
+
+ /**
+ * Construct an empty TimerStat object with the count and time set to 0.
+ */
+ public TimerStat() {
+ }
+
+ /**
+ * Construct a TimerStat object with the supplied count and time fields.
+ *
+ * @param count The count
+ * @param time The time
+ */
+ public TimerStat(int count, long time) {
+ mCount = count;
+ mTime = time;
+ }
+
+ /**
+ * Construct a TimerStat object reading the values from a {@link android.os.Parcel Parcel}
+ * object.
+ */
+ public TimerStat(Parcel in) {
+ mCount = in.readInt();
+ mTime = in.readLong();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Write this TimerStat object to a parcel.
+ */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mCount);
+ out.writeLong(mTime);
+ }
+
+ /**
+ * Set the count for this timer.
+ */
+ public void setCount(int count) {
+ mCount = count;
+ }
+
+ /**
+ * Get the count for this timer.
+ */
+ public int getCount() {
+ return mCount;
+ }
+
+ /**
+ * Set the time for this timer.
+ */
+ public void setTime(long time) {
+ mTime = time;
+ }
+
+ /**
+ * Get the time for this timer.
+ */
+ public long getTime() {
+ return mTime;
+ }
+}
diff --git a/core/java/android/os/health/UidHealthStats.java b/core/java/android/os/health/UidHealthStats.java
new file mode 100644
index 0000000..c7d257f
--- /dev/null
+++ b/core/java/android/os/health/UidHealthStats.java
@@ -0,0 +1,280 @@
+/*
+ * 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.health;
+
+/**
+ * Keys for {@link HealthStats} returned from
+ * {@link SystemHealthManager#takeUidSnapshot(int) SystemHealthManager.takeUidSnapshot(int)},
+ * {@link SystemHealthManager#takeMyUidSnapshot() SystemHealthManager.takeMyUidSnapshot()}, and
+ * {@link SystemHealthManager#takeUidSnapshots(int[]) SystemHealthManager.takeUidSnapshots(int[])}.
+ */
+public final class UidHealthStats {
+
+ private UidHealthStats() {
+ }
+
+ /**
+ * How many milliseconds this statistics report covers in wall-clock time while the
+ * device was on battery including both screen-on and screen-off time.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_REALTIME_BATTERY_MS = HealthKeys.BASE_UID + 1;
+
+ /**
+ * How many milliseconds this statistics report covers that the CPU was running while the
+ * device was on battery including both screen-on and screen-off time.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_UPTIME_BATTERY_MS = HealthKeys.BASE_UID + 2;
+
+ /**
+ * How many milliseconds this statistics report covers in wall-clock time while the
+ * device was on battery including both screen-on and screen-off time.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 3;
+
+ /**
+ * How many milliseconds this statistics report covers that the CPU was running while the
+ * device was on battery including both screen-on and screen-off time.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS = HealthKeys.BASE_UID + 4;
+
+ /**
+ * Key for a TimerStat for the times a
+ * {@link android.os.PowerManager#FULL_WAKE_LOCK full wake lock}
+ * was acquired for this uid.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+ public static final int TIMERS_WAKELOCKS_FULL = HealthKeys.BASE_UID + 5;
+
+ /**
+ * Key for a TimerStat for the times a
+ * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK full wake lock}
+ * was acquired for this uid.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+ public static final int TIMERS_WAKELOCKS_PARTIAL = HealthKeys.BASE_UID + 6;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+ public static final int TIMERS_WAKELOCKS_WINDOW = HealthKeys.BASE_UID + 7;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+ public static final int TIMERS_WAKELOCKS_DRAW = HealthKeys.BASE_UID + 8;
+
+ /**
+ * Key for a map of Timers for the sync adapter syncs that were done for
+ * this uid.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+ public static final int TIMERS_SYNCS = HealthKeys.BASE_UID + 9;
+
+ /**
+ * Key for a map of Timers for the {@link android.app.job.JobScheduler} jobs for
+ * this uid.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+ public static final int TIMERS_JOBS = HealthKeys.BASE_UID + 10;
+
+ /**
+ * Key for a timer for the applications use of the GPS sensor.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_GPS_SENSOR = HealthKeys.BASE_UID + 11;
+
+ /**
+ * Key for a map of the sensor usage for this uid. The keys are a
+ * string representation of the handle for the sensor.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMERS)
+ public static final int TIMERS_SENSORS = HealthKeys.BASE_UID + 12;
+
+ /**
+ * Key for a HealthStats with {@link PidHealthStats} keys for each of the
+ * currently running processes for this uid.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_STATS)
+ public static final int STATS_PIDS = HealthKeys.BASE_UID + 13;
+
+ /**
+ * Key for a HealthStats with {@link ProcessHealthStats} keys for each of the
+ * named processes for this uid.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_STATS)
+ public static final int STATS_PROCESSES = HealthKeys.BASE_UID + 14;
+
+ /**
+ * Key for a HealthStats with {@link PackageHealthStats} keys for each of the
+ * APKs that share this uid.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_STATS)
+ public static final int STATS_PACKAGES = HealthKeys.BASE_UID + 15;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_IDLE_MS = HealthKeys.BASE_UID + 16;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_RX_MS = HealthKeys.BASE_UID + 17;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_TX_MS = HealthKeys.BASE_UID + 18;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_POWER_MAMS = HealthKeys.BASE_UID + 19;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_BLUETOOTH_IDLE_MS = HealthKeys.BASE_UID + 20;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_BLUETOOTH_RX_MS = HealthKeys.BASE_UID + 21;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_BLUETOOTH_TX_MS = HealthKeys.BASE_UID + 22;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_BLUETOOTH_POWER_MAMS = HealthKeys.BASE_UID + 23;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_MOBILE_IDLE_MS = HealthKeys.BASE_UID + 24;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_MOBILE_RX_MS = HealthKeys.BASE_UID + 25;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_MOBILE_TX_MS = HealthKeys.BASE_UID + 26;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_MOBILE_POWER_MAMS = HealthKeys.BASE_UID + 27;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_RUNNING_MS = HealthKeys.BASE_UID + 28;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_FULL_LOCK_MS = HealthKeys.BASE_UID + 29;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_WIFI_SCAN = HealthKeys.BASE_UID + 30;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_MULTICAST_MS = HealthKeys.BASE_UID + 31;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_AUDIO = HealthKeys.BASE_UID + 32;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_VIDEO = HealthKeys.BASE_UID + 33;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_FLASHLIGHT = HealthKeys.BASE_UID + 34;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_CAMERA = HealthKeys.BASE_UID + 35;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_FOREGROUND_ACTIVITY = HealthKeys.BASE_UID + 36;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_BLUETOOTH_SCAN = HealthKeys.BASE_UID + 37;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_PROCESS_STATE_TOP_MS = HealthKeys.BASE_UID + 38;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS = HealthKeys.BASE_UID + 39;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_PROCESS_STATE_TOP_SLEEPING_MS = HealthKeys.BASE_UID + 40;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_PROCESS_STATE_FOREGROUND_MS = HealthKeys.BASE_UID + 41;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_PROCESS_STATE_BACKGROUND_MS = HealthKeys.BASE_UID + 42;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_PROCESS_STATE_CACHED_MS = HealthKeys.BASE_UID + 43;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_VIBRATOR = HealthKeys.BASE_UID + 44;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_OTHER_USER_ACTIVITY_COUNT = HealthKeys.BASE_UID + 45;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT = HealthKeys.BASE_UID + 46;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT = HealthKeys.BASE_UID + 47;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_MOBILE_RX_BYTES = HealthKeys.BASE_UID + 48;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_MOBILE_TX_BYTES = HealthKeys.BASE_UID + 49;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_RX_BYTES = HealthKeys.BASE_UID + 50;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_TX_BYTES = HealthKeys.BASE_UID + 51;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_BLUETOOTH_RX_BYTES = HealthKeys.BASE_UID + 52;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_BLUETOOTH_TX_BYTES = HealthKeys.BASE_UID + 53;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_MOBILE_RX_PACKETS = HealthKeys.BASE_UID + 54;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_MOBILE_TX_PACKETS = HealthKeys.BASE_UID + 55;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_RX_PACKETS = HealthKeys.BASE_UID + 56;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_WIFI_TX_PACKETS = HealthKeys.BASE_UID + 57;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_BLUETOOTH_RX_PACKETS = HealthKeys.BASE_UID + 58;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_BLUETOOTH_TX_PACKETS = HealthKeys.BASE_UID + 59;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_TIMER)
+ public static final int TIMER_MOBILE_RADIO_ACTIVE = HealthKeys.BASE_UID + 61;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_USER_CPU_TIME_US = HealthKeys.BASE_UID + 62;
+
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_SYSTEM_CPU_TIME_US = HealthKeys.BASE_UID + 63;
+
+ /**
+ * An estimate of the number of milliamp-microsends used by this uid.
+ */
+ @HealthKeys.Constant(type=HealthKeys.TYPE_MEASUREMENT)
+ public static final int MEASUREMENT_CPU_POWER_MAUS = HealthKeys.BASE_UID + 64;
+
+ /**
+ * @hide
+ */
+ public static final HealthKeys.Constants CONSTANTS = new HealthKeys.Constants(UidHealthStats.class);
+}
+
diff --git a/core/java/android/os/health/package.html b/core/java/android/os/health/package.html
new file mode 100644
index 0000000..3a46a5b
--- /dev/null
+++ b/core/java/android/os/health/package.html
@@ -0,0 +1,39 @@
+<html>
+<body>
+
+The android.os.health package contains a set of classes to provide data
+to track the system resources of applications.
+<p>
+Applications running in the background are responsible for a significant amount
+of battery usage on a typical android device. There are several things that
+applications can do in order to reduce their impact. For example, by using
+{@link android.app.job.JobScheduler JobScheduler}, an application does not need
+to independently monitor whether the network is available, whether the device is
+plugged in, etc. In addition to being simpler to use, the application's
+services are only started when the required conditions have been met. But even
+when using the appropriate helper APIs, applications still can reduce their
+footprint. This package provides more insight into what is going on behind the
+scenes when an application is running.
+<p>
+Application data is tracked by which user id (uid) is using particular
+resources. A snapshot of an application's measurements can be taken with the
+{@link android.os.health.SystemHealthManager#takeMyUidSnapshot() SystemHealth.takeMyUidSnapshot()}
+method. The {@link android.os.health.HealthStats} object returned contains the
+statistics.
+<p>
+<b>HealthStats</b><br>
+In order to be returned efficiently, the {@link android.os.health.HealthStats}
+class uses a set of int keys to identify the data returned. The
+{@link android.os.health.UidHealthStats}, {@link android.os.health.PidHealthStats},
+{@link android.os.health.PackageHealthStats} , {@link android.os.health.ProcessHealthStats},
+and {@link android.os.health.ServiceHealthStats} classes provide those constants.
+Each {@link android.os.health.HealthStats} object will be associated with
+exactly one of those classes. The object returned from
+{@link android.os.health.SystemHealthManager#takeMyUidSnapshot() SystemHealth.takeMyUidSnapshot()}
+will be using the {@link android.os.health.UidHealthStats} keys, as it contains all
+of the data available for that uid.
+
+
+</body>
+</html>
+
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index fc440d2..c21c65a 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -2286,7 +2286,12 @@
/**
* Determines the encryption state of the volume.
- * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible values.
+ * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible
+ * values.
+ * Note that this has been replaced in most cases by the APIs in
+ * StorageManager (see isEncryptable and below)
+ * This is still useful to get the error state when encryption has failed
+ * and CryptKeeper needs to throw up a screen advising the user what to do
*/
public int getEncryptionState() throws RemoteException;
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 17df708..61e6b95 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1025,21 +1025,119 @@
}
}
- /** {@hide} */
- public static boolean isFileBasedEncryptionEnabled() {
- return isNativeFileBasedEncryptionEnabled() || isEmulatedFileBasedEncryptionEnabled();
+ /** {@hide}
+ * Is this device encryptable or already encrypted?
+ * @return true for encryptable or encrypted
+ * false not encrypted and not encryptable
+ */
+ public static boolean isEncryptable() {
+ final String state = SystemProperties.get("ro.crypto.state", "unsupported");
+ return !"unsupported".equalsIgnoreCase(state);
+ }
+
+ /** {@hide}
+ * Is this device already encrypted?
+ * @return true for encrypted. (Implies isEncryptable() == true)
+ * false not encrypted
+ */
+ public static boolean isEncrypted() {
+ final String state = SystemProperties.get("ro.crypto.state", "");
+ return "encrypted".equalsIgnoreCase(state);
+ }
+
+ /** {@hide}
+ * Is this device file encrypted?
+ * @return true for file encrypted. (Implies isEncrypted() == true)
+ * false not encrypted or block encrypted
+ */
+ public static boolean isFileEncryptedNativeOnly() {
+ if (!isEncrypted()) {
+ return false;
+ }
+
+ final String status = SystemProperties.get("ro.crypto.type", "");
+ return "file".equalsIgnoreCase(status);
+ }
+
+ /** {@hide}
+ * Is this device block encrypted?
+ * @return true for block encrypted. (Implies isEncrypted() == true)
+ * false not encrypted or file encrypted
+ */
+ public static boolean isBlockEncrypted() {
+ if (!isEncrypted()) {
+ return false;
+ }
+ final String status = SystemProperties.get("ro.crypto.type", "");
+ return "block".equalsIgnoreCase(status);
+ }
+
+ /** {@hide}
+ * Is this device block encrypted with credentials?
+ * @return true for crediential block encrypted.
+ * (Implies isBlockEncrypted() == true)
+ * false not encrypted, file encrypted or default block encrypted
+ */
+ public static boolean isNonDefaultBlockEncrypted() {
+ if (!isBlockEncrypted()) {
+ return false;
+ }
+
+ try {
+ IMountService mountService = IMountService.Stub.asInterface(
+ ServiceManager.getService("mount"));
+ return mountService.getPasswordType() != CRYPT_TYPE_DEFAULT;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error getting encryption type");
+ return false;
+ }
+ }
+
+ /** {@hide}
+ * Is this device in the process of being block encrypted?
+ * @return true for encrypting.
+ * false otherwise
+ * Whether device isEncrypted at this point is undefined
+ * Note that only system services and CryptKeeper will ever see this return
+ * true - no app will ever be launched in this state.
+ * Also note that this state will not change without a teardown of the
+ * framework, so no service needs to check for changes during their lifespan
+ */
+ public static boolean isBlockEncrypting() {
+ final String state = SystemProperties.get("vold.encrypt_progress", "");
+ return !"".equalsIgnoreCase(state);
+ }
+
+ /** {@hide}
+ * Is this device non default block encrypted and in the process of
+ * prompting for credentials?
+ * @return true for prompting for credentials.
+ * (Implies isNonDefaultBlockEncrypted() == true)
+ * false otherwise
+ * Note that only system services and CryptKeeper will ever see this return
+ * true - no app will ever be launched in this state.
+ * Also note that this state will not change without a teardown of the
+ * framework, so no service needs to check for changes during their lifespan
+ */
+ public static boolean inCryptKeeperBounce() {
+ final String status = SystemProperties.get("vold.decrypt");
+ return "trigger_restart_min_framework".equals(status);
}
/** {@hide} */
- public static boolean isNativeFileBasedEncryptionEnabled() {
- return "file".equals(SystemProperties.get("ro.crypto.type", "none"));
- }
-
- /** {@hide} */
- public static boolean isEmulatedFileBasedEncryptionEnabled() {
+ public static boolean isFileEncryptedEmulatedOnly() {
return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
}
+ /** {@hide}
+ * Is this device running in a file encrypted mode, either native or emulated?
+ * @return true for file encrypted, false otherwise
+ */
+ public static boolean isFileEncryptedNativeOrEmulated() {
+ return isFileEncryptedNativeOnly()
+ || isFileEncryptedEmulatedOnly();
+ }
+
/** {@hide} */
public static File maybeTranslateEmulatedPathToInternal(File path) {
final IMountService mountService = IMountService.Stub.asInterface(
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index 0439fe2..def303a 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -29,11 +29,14 @@
* <p>
* The content provider exposes a table containing blocked numbers. The columns and URIs for
* accessing this table are defined by the {@link BlockedNumbers} class. Messages, and calls from
- * blocked numbers are discarded by the platform. If the user contacts emergency
- * services, number blocking is disabled by the platform for a duration defined by
+ * blocked numbers are discarded by the platform. Notifications upon provider changes can be
+ * received using a {@link android.database.ContentObserver}.
+ * </p>
+ * <p>
+ * The platform will not block messages, and calls from emergency numbers as defined by
+ * {@link android.telephony.PhoneNumberUtils#isEmergencyNumber(String)}. If the user contacts
+ * emergency services, number blocking is disabled by the platform for a duration defined by
* {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT}.
- * Notifications upon provider changes can be received using a
- * {@link android.database.ContentObserver}.
* </p>
*
* <h3> Permissions </h3>
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 4b43f53..3658df9 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -5185,6 +5185,10 @@
* <li>
* Corp contacts will get artificial {@link #LOOKUP_KEY}s too.
* </li>
+ * <li>
+ * Returned work contact IDs and lookup keys are not accepted in places that not
+ * explicitly say to accept them.
+ * </li>
* </ul>
* <p>
* A contact lookup URL built by
@@ -6194,6 +6198,10 @@
* <li>
* Corp contacts will get artificial {@link #LOOKUP_KEY}s too.
* </li>
+ * <li>
+ * Returned work contact IDs and lookup keys are not accepted in places that not
+ * explicitly say to accept them.
+ * </li>
* </ul>
* <p>
* A contact lookup URL built by
@@ -8466,7 +8474,9 @@
* around this {@link View}.
* @param lookupUri A {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
* {@link Uri} that describes a specific contact to feature
- * in this dialog.
+ * in this dialog. A work lookup uri is supported here,
+ * see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
+ * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
* @param mode Any of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or
* {@link #MODE_LARGE}, indicating the desired dialog size,
* when supported.
@@ -8500,7 +8510,9 @@
* @param lookupUri A
* {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
* {@link Uri} that describes a specific contact to feature
- * in this dialog.
+ * in this dialog. A work lookup uri is supported here,
+ * see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
+ * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
* @param mode Any of {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or
* {@link #MODE_LARGE}, indicating the desired dialog size,
* when supported.
@@ -8531,7 +8543,9 @@
* @param lookupUri A
* {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
* {@link Uri} that describes a specific contact to feature
- * in this dialog.
+ * in this dialog. A work lookup uri is supported here,
+ * see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
+ * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
* @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
* to exclude when showing this dialog. For example, when
* already viewing the contact details card, this can be used
@@ -8569,7 +8583,9 @@
* @param lookupUri A
* {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
* {@link Uri} that describes a specific contact to feature
- * in this dialog.
+ * in this dialog. A work lookup uri is supported here,
+ * see {@link CommonDataKinds.Email#ENTERPRISE_CONTENT_LOOKUP_URI} and
+ * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
* @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
* to exclude when showing this dialog. For example, when
* already viewing the contact details card, this can be used
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d43ff4e..d4ff766 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7786,6 +7786,31 @@
public static final String ALARM_MANAGER_CONSTANTS = "alarm_manager_constants";
/**
+ * ShortcutManager specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "reset_interval_sec=86400,max_daily_updates=5"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * reset_interval_sec (long)
+ * max_daily_updates (int)
+ * max_icon_dimension_dp (int, DP)
+ * max_icon_dimension_dp_lowram (int, DP)
+ * max_shortcuts (int)
+ * icon_quality (int, 0-100)
+ * icon_format (String)
+ * </pre>
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * @see com.android.server.pm.ShortcutService.ConfigConstants
+ */
+ public static final String SHORTCUT_MANAGER_CONSTANTS = "shortcut_manager_constants";
+
+ /**
* Get the key that retrieves a bluetooth headset's priority.
* @hide
*/
diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java
index 2a8773c..d57d0f5 100644
--- a/core/java/android/security/net/config/XmlConfigSource.java
+++ b/core/java/android/security/net/config/XmlConfigSource.java
@@ -339,7 +339,7 @@
}
if (mDebugBuild) {
debugConfigBuilder =
- parseConfigEntry(parser, seenDomains, null, CONFIG_DEBUG).get(0).first;
+ parseConfigEntry(parser, null, null, CONFIG_DEBUG).get(0).first;
} else {
XmlUtils.skipCurrentTag(parser);
}
@@ -348,6 +348,11 @@
XmlUtils.skipCurrentTag(parser);
}
}
+ // If debug is true and there was no debug-overrides in the file check for an extra
+ // _debug resource.
+ if (mDebugBuild && debugConfigBuilder == null) {
+ debugConfigBuilder = parseDebugOverridesResource();
+ }
// Use the platform default as the parent of the base config for any values not provided
// there. If there is no base config use the platform default.
@@ -385,6 +390,43 @@
mDomainMap = configs;
}
+ private NetworkSecurityConfig.Builder parseDebugOverridesResource()
+ throws IOException, XmlPullParserException, ParserException {
+ Resources resources = mContext.getResources();
+ String packageName = resources.getResourcePackageName(mResourceId);
+ String entryName = resources.getResourceEntryName(mResourceId);
+ int resId = resources.getIdentifier(entryName + "_debug", "xml", packageName);
+ // No debug-overrides resource was found, nothing to parse.
+ if (resId == 0) {
+ return null;
+ }
+ NetworkSecurityConfig.Builder debugConfigBuilder = null;
+ // Parse debug-overrides out of the _debug resource.
+ try (XmlResourceParser parser = resources.getXml(resId)) {
+ XmlUtils.beginDocument(parser, "network-security-config");
+ int outerDepth = parser.getDepth();
+ boolean seenDebugOverrides = false;
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if ("debug-overrides".equals(parser.getName())) {
+ if (seenDebugOverrides) {
+ throw new ParserException(parser, "Only one debug-overrides allowed");
+ }
+ if (mDebugBuild) {
+ debugConfigBuilder =
+ parseConfigEntry(parser, null, null, CONFIG_DEBUG).get(0).first;
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ seenDebugOverrides = true;
+ } else {
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ return debugConfigBuilder;
+ }
+
public static class ParserException extends Exception {
public ParserException(XmlPullParser parser, String message, Throwable cause) {
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a8b8da1..afdd1d4 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -680,18 +680,12 @@
@SystemApi
public void registerAsSystemService(Context context, ComponentName componentName,
int currentUser) throws RemoteException {
- registerAsSystemServiceImpl(context, componentName, currentUser, false /* asRanker */);
- }
-
- /** @hide */
- protected void registerAsSystemServiceImpl(Context context, ComponentName componentName,
- int currentUser, boolean asRanker) throws RemoteException {
- mSystemContext = context;
if (mWrapper == null) {
mWrapper = new NotificationListenerWrapper();
}
+ mSystemContext = context;
INotificationManager noMan = getNotificationInterface();
- noMan.registerListener(mWrapper, componentName, currentUser, asRanker);
+ noMan.registerListener(mWrapper, componentName, currentUser);
mCurrentUser = currentUser;
mHandler = new MyHandler(context.getMainLooper());
}
diff --git a/core/java/android/service/notification/NotificationRankerService.java b/core/java/android/service/notification/NotificationRankerService.java
index 520b4c2..e325354 100644
--- a/core/java/android/service/notification/NotificationRankerService.java
+++ b/core/java/android/service/notification/NotificationRankerService.java
@@ -37,7 +37,7 @@
*/
@SystemApi
public abstract class NotificationRankerService extends NotificationListenerService {
- private static final String TAG = "NotificationRanker";
+ private static final String TAG = "NotificationRankers";
/**
* The {@link Intent} that must be declared as handled by the service.
@@ -118,9 +118,8 @@
/** @hide */
@Override
public void registerAsSystemService(Context context, ComponentName componentName,
- int currentUser) throws RemoteException {
- registerAsSystemServiceImpl(context, componentName, currentUser, true /* as Ranker */);
- mHandler = new MyHandler(getContext().getMainLooper());
+ int currentUser) {
+ throw new IllegalStateException("the ranker may not start itself.");
}
@Override
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c54ce80..d29bc21 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5357,9 +5357,6 @@
void offsetRectBetweenParentAndChild(View descendant, Rect rect,
boolean offsetFromChildToParent, boolean clipToBounds) {
- final RectF rectF = mAttachInfo != null ? mAttachInfo.mTmpTransformRect1 : new RectF();
- final Matrix inverse = mAttachInfo != null ? mAttachInfo.mTmpMatrix : new Matrix();
-
// already in the same coord system :)
if (descendant == this) {
return;
@@ -5373,16 +5370,8 @@
&& (theParent != this)) {
if (offsetFromChildToParent) {
- rect.offset(-descendant.mScrollX, -descendant.mScrollY);
-
- if (!descendant.hasIdentityMatrix()) {
- rectF.set(rect);
- descendant.getMatrix().mapRect(rectF);
- rectF.roundOut(rect);
- }
-
- rect.offset(descendant.mLeft, descendant.mTop);
-
+ rect.offset(descendant.mLeft - descendant.mScrollX,
+ descendant.mTop - descendant.mScrollY);
if (clipToBounds) {
View p = (View) theParent;
boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
@@ -5400,16 +5389,8 @@
rect.setEmpty();
}
}
- rect.offset(-descendant.mLeft, -descendant.mTop);
-
- if (!descendant.hasIdentityMatrix()) {
- descendant.getMatrix().invert(inverse);
- rectF.set(rect);
- inverse.mapRect(rectF);
- rectF.roundOut(rect);
- }
-
- rect.offset(descendant.mScrollX, descendant.mScrollY);
+ rect.offset(descendant.mScrollX - descendant.mLeft,
+ descendant.mScrollY - descendant.mTop);
}
descendant = (View) theParent;
@@ -5420,26 +5401,11 @@
// to get into our coordinate space
if (theParent == this) {
if (offsetFromChildToParent) {
- rect.offset(-descendant.mScrollX, -descendant.mScrollY);
-
- if (!descendant.hasIdentityMatrix()) {
- rectF.set(rect);
- descendant.getMatrix().mapRect(rectF);
- rectF.roundOut(rect);
- }
-
- rect.offset(descendant.mLeft, descendant.mTop);
+ rect.offset(descendant.mLeft - descendant.mScrollX,
+ descendant.mTop - descendant.mScrollY);
} else {
- rect.offset(-descendant.mLeft, -descendant.mTop);
-
- if (!descendant.hasIdentityMatrix()) {
- descendant.getMatrix().invert(inverse);
- rectF.set(rect);
- inverse.mapRect(rectF);
- rectF.roundOut(rect);
- }
-
- rect.offset(descendant.mScrollX, descendant.mScrollY);
+ rect.offset(descendant.mScrollX - descendant.mLeft,
+ descendant.mScrollY - descendant.mTop);
}
} else {
throw new IllegalArgumentException("parameter must be a descendant of this view");
diff --git a/core/java/android/view/ViewGroupOverlay.java b/core/java/android/view/ViewGroupOverlay.java
index 16afc5d..c2807ba 100644
--- a/core/java/android/view/ViewGroupOverlay.java
+++ b/core/java/android/view/ViewGroupOverlay.java
@@ -15,6 +15,7 @@
*/
package android.view;
+import android.annotation.NonNull;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -37,7 +38,7 @@
}
/**
- * Adds a View to the overlay. The bounds of the added view should be
+ * Adds a {@code View} to the overlay. The bounds of the added view should be
* relative to the host view. Any view added to the overlay should be
* removed when it is no longer needed or no longer visible.
*
@@ -54,23 +55,32 @@
* and 200 pixels down from the origin of the overlay's
* host view, then the view will be offset by (100, 200).</p>
*
- * @param view The View to be added to the overlay. The added view will be
+ * <p>{@code View}s added with this API will be drawn in the order they were
+ * added. Drawing of the overlay views will happen before drawing of any of the
+ * {@code Drawable}s added with {@link #add(Drawable)} API even if a call to
+ * this API happened after the call to {@link #add(Drawable)}.</p>
+ *
+ * <p>Passing <code>null</code> parameter will result in an
+ * {@link IllegalArgumentException} being thrown.</p>
+ *
+ * @param view The {@code View} to be added to the overlay. The added view will be
* drawn when the overlay is drawn.
* @see #remove(View)
* @see ViewOverlay#add(Drawable)
*/
- public void add(View view) {
+ public void add(@NonNull View view) {
mOverlayViewGroup.add(view);
}
/**
- * Removes the specified View from the overlay.
+ * Removes the specified {@code View} from the overlay. Passing <code>null</code> parameter
+ * will result in an {@link IllegalArgumentException} being thrown.
*
- * @param view The View to be removed from the overlay.
+ * @param view The {@code View} to be removed from the overlay.
* @see #add(View)
* @see ViewOverlay#remove(Drawable)
*/
- public void remove(View view) {
+ public void remove(@NonNull View view) {
mOverlayViewGroup.remove(view);
}
}
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 5e5ef29..0d05c54 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -16,6 +16,7 @@
package android.view;
import android.animation.LayoutTransition;
+import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -59,25 +60,30 @@
}
/**
- * Adds a Drawable to the overlay. The bounds of the drawable should be relative to
+ * Adds a {@link Drawable} to the overlay. The bounds of the drawable should be relative to
* the host view. Any drawable added to the overlay should be removed when it is no longer
- * needed or no longer visible.
+ * needed or no longer visible. Adding an already existing {@link Drawable}
+ * is a no-op. Passing <code>null</code> parameter will result in an
+ * {@link IllegalArgumentException} being thrown.
*
- * @param drawable The Drawable to be added to the overlay. This drawable will be
- * drawn when the view redraws its overlay.
+ * @param drawable The {@link Drawable} to be added to the overlay. This drawable will be
+ * drawn when the view redraws its overlay. {@link Drawable}s will be drawn in the order that
+ * they were added.
* @see #remove(Drawable)
*/
- public void add(Drawable drawable) {
+ public void add(@NonNull Drawable drawable) {
mOverlayViewGroup.add(drawable);
}
/**
- * Removes the specified Drawable from the overlay.
+ * Removes the specified {@link Drawable} from the overlay. Removing a {@link Drawable} that was
+ * not added with {@link #add(Drawable)} is a no-op. Passing <code>null</code> parameter will
+ * result in an {@link IllegalArgumentException} being thrown.
*
- * @param drawable The Drawable to be removed from the overlay.
+ * @param drawable The {@link Drawable} to be removed from the overlay.
* @see #add(Drawable)
*/
- public void remove(Drawable drawable) {
+ public void remove(@NonNull Drawable drawable) {
mOverlayViewGroup.remove(drawable);
}
@@ -119,7 +125,7 @@
* The View for which this is an overlay. Invalidations of the overlay are redirected to
* this host view.
*/
- View mHostView;
+ final View mHostView;
/**
* The set of drawables to draw when the overlay is rendered.
@@ -137,10 +143,12 @@
mRenderNode.setLeftTopRightBottom(0, 0, mRight, mBottom);
}
- public void add(Drawable drawable) {
+ public void add(@NonNull Drawable drawable) {
+ if (drawable == null) {
+ throw new IllegalArgumentException("drawable must be non-null");
+ }
if (mDrawables == null) {
-
- mDrawables = new ArrayList<Drawable>();
+ mDrawables = new ArrayList<>();
}
if (!mDrawables.contains(drawable)) {
// Make each drawable unique in the overlay; can't add it more than once
@@ -150,7 +158,10 @@
}
}
- public void remove(Drawable drawable) {
+ public void remove(@NonNull Drawable drawable) {
+ if (drawable == null) {
+ throw new IllegalArgumentException("drawable must be non-null");
+ }
if (mDrawables != null) {
mDrawables.remove(drawable);
invalidate(drawable.getBounds());
@@ -163,7 +174,11 @@
return super.verifyDrawable(who) || (mDrawables != null && mDrawables.contains(who));
}
- public void add(View child) {
+ public void add(@NonNull View child) {
+ if (child == null) {
+ throw new IllegalArgumentException("view must be non-null");
+ }
+
if (child.getParent() instanceof ViewGroup) {
ViewGroup parent = (ViewGroup) child.getParent();
if (parent != mHostView && parent.getParent() != null &&
@@ -190,7 +205,11 @@
super.addView(child);
}
- public void remove(View view) {
+ public void remove(@NonNull View view) {
+ if (view == null) {
+ throw new IllegalArgumentException("view must be non-null");
+ }
+
super.removeView(view);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6e02516..17f1991 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -135,6 +135,18 @@
}
/**
+ * Message for taking fullscreen screenshot
+ * @hide
+ */
+ final int TAKE_SCREENSHOT_FULLSCREEN = 1;
+
+ /**
+ * Message for taking screenshot of selected region.
+ * @hide
+ */
+ final int TAKE_SCREENSHOT_SELECTED_REGION = 2;
+
+ /**
* @hide
*/
public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array";
@@ -269,6 +281,7 @@
@ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"),
@ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER, to = "TYPE_DOCK_DIVIDER"),
@ViewDebug.IntToString(from = TYPE_QS_DIALOG, to = "TYPE_QS_DIALOG"),
+ @ViewDebug.IntToString(from = TYPE_SCREENSHOT, to = "TYPE_SCREENSHOT")
})
public int type;
@@ -622,6 +635,13 @@
public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35;
/**
+ * Window type: shares similar characteristics with {@link #TYPE_DREAM}. The layer is
+ * reserved for screenshot region selection.
+ * @hide
+ */
+ public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index 471b6d4..fc17f7a 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -31,10 +31,12 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
+import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.Xml;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
@@ -55,7 +57,7 @@
/**
* The array of subtypes.
*/
- private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<SpellCheckerSubtype>();
+ private final ArrayList<SpellCheckerSubtype> mSubtypes = new ArrayList<>();
/**
* Constructor.
@@ -267,4 +269,22 @@
public int describeContents() {
return 0;
}
+
+ /**
+ * @hide
+ */
+ public void dump(final PrintWriter pw, final String prefix) {
+ pw.println(prefix + "mId=" + mId);
+ pw.println(prefix + "mSettingsActivityName=" + mSettingsActivityName);
+ pw.println(prefix + "Service:");
+ mService.dump(new PrintWriterPrinter(pw), prefix + " ");
+ final int N = getSubtypeCount();
+ for (int i = 0; i < N; i++) {
+ final SpellCheckerSubtype st = getSubtypeAt(i);
+ pw.println(prefix + " " + "Subtype #" + i + ":");
+ pw.println(prefix + " " + "locale=" + st.getLocale()
+ + " languageTag=" + st.getLanguageTag());
+ pw.println(prefix + " " + "extraValue=" + st.getExtraValue());
+ }
+ }
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index ad50ff6..3d72260 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -262,11 +262,11 @@
"For security reasons, WebView is not allowed in privileged processes");
}
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
try {
Class<WebViewFactoryProvider> providerClass = getProviderClass();
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
try {
sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
@@ -278,10 +278,10 @@
throw new AndroidRuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
- StrictMode.setThreadPolicy(oldPolicy);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ StrictMode.setThreadPolicy(oldPolicy);
}
}
}
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index f5840dc..8ce2f9c 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -282,7 +282,7 @@
public CharSequence getPageTitle(int position) {
final SimpleMonthView v = mItems.get(position).calendar;
if (v != null) {
- return v.getTitle();
+ return v.getMonthYearLabel();
}
return null;
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 406dc2b..6959137 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2395,17 +2395,22 @@
dragSourceEnd += shift;
}
- // Delete original selection
- mTextView.deleteText_internal(dragSourceStart, dragSourceEnd);
+ mUndoInputFilter.setForceMerge(true);
+ try {
+ // Delete original selection
+ mTextView.deleteText_internal(dragSourceStart, dragSourceEnd);
- // Make sure we do not leave two adjacent spaces.
- final int prevCharIdx = Math.max(0, dragSourceStart - 1);
- final int nextCharIdx = Math.min(mTextView.getText().length(), dragSourceStart + 1);
- if (nextCharIdx > prevCharIdx + 1) {
- CharSequence t = mTextView.getTransformedText(prevCharIdx, nextCharIdx);
- if (Character.isSpaceChar(t.charAt(0)) && Character.isSpaceChar(t.charAt(1))) {
- mTextView.deleteText_internal(prevCharIdx, prevCharIdx + 1);
+ // Make sure we do not leave two adjacent spaces.
+ final int prevCharIdx = Math.max(0, dragSourceStart - 1);
+ final int nextCharIdx = Math.min(mTextView.getText().length(), dragSourceStart + 1);
+ if (nextCharIdx > prevCharIdx + 1) {
+ CharSequence t = mTextView.getTransformedText(prevCharIdx, nextCharIdx);
+ if (Character.isSpaceChar(t.charAt(0)) && Character.isSpaceChar(t.charAt(1))) {
+ mTextView.deleteText_internal(prevCharIdx, prevCharIdx + 1);
+ }
}
+ } finally {
+ mUndoInputFilter.setForceMerge(false);
}
}
}
@@ -5497,6 +5502,9 @@
// rotates the screen during composition.
private boolean mHasComposition;
+ // Whether to merge events into one operation.
+ private boolean mForceMerge;
+
public UndoInputFilter(Editor editor) {
mEditor = editor;
}
@@ -5511,6 +5519,10 @@
mHasComposition = parcel.readInt() != 0;
}
+ public void setForceMerge(boolean forceMerge) {
+ mForceMerge = forceMerge;
+ }
+
/**
* Signals that a user-triggered edit is starting.
*/
@@ -5570,7 +5582,7 @@
// Otherwise the user inserted the composition.
String newText = TextUtils.substring(source, start, end);
EditOperation edit = new EditOperation(mEditor, "", dstart, newText);
- recordEdit(edit, false /* forceMerge */);
+ recordEdit(edit, mForceMerge);
return true;
}
@@ -5584,7 +5596,7 @@
// the initial input filters run (e.g. a credit card formatter that adds spaces to a
// string). This results in multiple filter() calls for what the user considers to be
// a single operation. Always undo the whole set of changes in one step.
- final boolean forceMerge = isInTextWatcher();
+ final boolean forceMerge = mForceMerge || isInTextWatcher();
// Build a new operation with all the information from this edit.
String newText = TextUtils.substring(source, start, end);
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 6edce91..8a7ce12 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -47,6 +47,7 @@
import com.android.internal.widget.ExploreByTouchHelper;
import java.text.NumberFormat;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
@@ -55,13 +56,15 @@
* within the specified month.
*/
class SimpleMonthView extends View {
+ private static final String LOG_TAG = "SimpleMonthView";
+
private static final int DAYS_IN_WEEK = 7;
private static final int MAX_WEEKS_IN_MONTH = 6;
private static final int DEFAULT_SELECTED_DAY = -1;
private static final int DEFAULT_WEEK_START = Calendar.SUNDAY;
- private static final String DEFAULT_TITLE_FORMAT = "MMMMy";
+ private static final String MONTH_YEAR_FORMAT = "MMMMy";
private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
private static final int SELECTED_HIGHLIGHT_ALPHA = 0xB0;
@@ -73,13 +76,13 @@
private final Paint mDayHighlightPaint = new Paint();
private final Paint mDayHighlightSelectorPaint = new Paint();
- private final Calendar mCalendar = Calendar.getInstance();
- private final Calendar mDayOfWeekLabelCalendar = Calendar.getInstance();
+ private final String[] mDayOfWeekLabels = new String[7];
+
+ private final Calendar mCalendar;
+ private final Locale mLocale;
private final MonthViewTouchHelper mTouchHelper;
- private final SimpleDateFormat mTitleFormatter;
- private final SimpleDateFormat mDayOfWeekFormatter;
private final NumberFormat mDayFormatter;
// Desired dimensions.
@@ -89,7 +92,7 @@
private final int mDesiredCellWidth;
private final int mDesiredDaySelectorRadius;
- private CharSequence mTitle;
+ private String mMonthYearLabel;
private int mMonth;
private int mYear;
@@ -168,15 +171,34 @@
setAccessibilityDelegate(mTouchHelper);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
- final Locale locale = res.getConfiguration().locale;
- final String titleFormat = DateFormat.getBestDateTimePattern(locale, DEFAULT_TITLE_FORMAT);
- mTitleFormatter = new SimpleDateFormat(titleFormat, locale);
- mDayOfWeekFormatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, locale);
- mDayFormatter = NumberFormat.getIntegerInstance(locale);
+ mLocale = res.getConfiguration().locale;
+ mCalendar = Calendar.getInstance(mLocale);
+
+ mDayFormatter = NumberFormat.getIntegerInstance(mLocale);
+
+ updateMonthYearLabel();
+ updateDayOfWeekLabels();
initPaints(res);
}
+ private void updateMonthYearLabel() {
+ final String format = DateFormat.getBestDateTimePattern(mLocale, MONTH_YEAR_FORMAT);
+ final SimpleDateFormat formatter = new SimpleDateFormat(format, mLocale);
+ mMonthYearLabel = formatter.format(mCalendar.getTime());
+ }
+
+ private void updateDayOfWeekLabels() {
+ final Calendar calendar = Calendar.getInstance(mLocale);
+ calendar.setFirstDayOfWeek(mWeekStart);
+
+ final SimpleDateFormat formatter = new SimpleDateFormat(DAY_OF_WEEK_FORMAT, mLocale);
+ for (int i = 0; i < 7; i++) {
+ calendar.set(Calendar.DAY_OF_WEEK, i);
+ mDayOfWeekLabels[i] = formatter.format(calendar.getTime());
+ }
+ }
+
/**
* Applies the specified text appearance resource to a paint, returning the
* text color if one is set in the text appearance.
@@ -236,13 +258,6 @@
invalidate();
}
- public CharSequence getTitle() {
- if (mTitle == null) {
- mTitle = mTitleFormatter.format(mCalendar.getTime());
- }
- return mTitle;
- }
-
/**
* Sets up the text and style properties for painting.
*/
@@ -607,7 +622,11 @@
final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent();
final float y = (mMonthHeight - lineHeight) / 2f;
- canvas.drawText(getTitle().toString(), x, y, mMonthPaint);
+ canvas.drawText(mMonthYearLabel, x, y, mMonthPaint);
+ }
+
+ public String getMonthYearLabel() {
+ return mMonthYearLabel;
}
private void drawDaysOfWeek(Canvas canvas) {
@@ -630,16 +649,11 @@
}
final int dayOfWeek = (col + mWeekStart) % DAYS_IN_WEEK;
- final String label = getDayOfWeekLabel(dayOfWeek);
+ final String label = mDayOfWeekLabels[dayOfWeek];
canvas.drawText(label, colCenterRtl, rowCenter - halfLineHeight, p);
}
}
- private String getDayOfWeekLabel(int dayOfWeek) {
- mDayOfWeekLabelCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
- return mDayOfWeekFormatter.format(mDayOfWeekLabelCalendar.getTime());
- }
-
/**
* Draws the month days.
*/
@@ -752,6 +766,8 @@
mWeekStart = mCalendar.getFirstDayOfWeek();
}
+ updateDayOfWeekLabels();
+
// Invalidate cached accessibility information.
mTouchHelper.invalidateRoot();
invalidate();
@@ -807,11 +823,10 @@
mEnabledDayStart = MathUtils.constrain(enabledDayStart, 1, mDaysInMonth);
mEnabledDayEnd = MathUtils.constrain(enabledDayEnd, mEnabledDayStart, mDaysInMonth);
- // Invalidate the old title.
- mTitle = null;
-
// Invalidate cached accessibility information.
mTouchHelper.invalidateRoot();
+
+ updateMonthYearLabel();
}
private static int getDaysInMonth(int month, int year) {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 74fe94f..8e38c5a 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -20,6 +20,7 @@
import android.os.ParcelFileDescriptor;
import android.os.WorkSource;
+import android.os.health.HealthStatsParceler;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.SignalStrength;
@@ -125,4 +126,7 @@
void noteBleScanStarted(in WorkSource ws);
void noteBleScanStopped(in WorkSource ws);
void noteResetBleScan();
+
+ HealthStatsParceler takeUidSnapshot(int uid);
+ HealthStatsParceler[] takeUidSnapshots(in int[] uid);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 60c9e14..c484121 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5300,6 +5300,12 @@
}
@Override
+ public Timer getProcessStateTimer(int state) {
+ if (state < 0 || state >= NUM_PROCESS_STATE) return null;
+ return mProcessStateTimer[state];
+ }
+
+ @Override
public Timer getVibratorOnTimer() {
return mVibratorOnTimer;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 795012d..9d14478 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -887,8 +887,7 @@
* @return true if device encryption is enabled
*/
public static boolean isDeviceEncryptionEnabled() {
- final String status = SystemProperties.get("ro.crypto.state", "unsupported");
- return "encrypted".equalsIgnoreCase(status);
+ return StorageManager.isEncrypted();
}
/**
@@ -896,7 +895,7 @@
* @return true if device is file encrypted
*/
public static boolean isFileEncryptionEnabled() {
- return StorageManager.isFileBasedEncryptionEnabled();
+ return StorageManager.isFileEncryptedNativeOrEmulated();
}
/**
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index ab75b7c..6d6c162 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.os.storage.StorageManager;
import android.provider.Downloads;
import android.util.AtomicFile;
import android.util.Slog;
@@ -143,8 +144,7 @@
HashMap<String, Long> timestamps = readTimestamps();
if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
- if ("encrypted".equals(SystemProperties.get("ro.crypto.state"))
- && "trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))) {
+ if (StorageManager.inCryptKeeperBounce()) {
// Encrypted, first boot to get PIN/pattern/password so data is tmpfs
// Don't set ro.runtime.firstboot so that we will do this again
// when data is properly mounted
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 29c1075..fb9b1e5 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -201,6 +201,26 @@
const unsigned int mSize;
};
+// Necessary for decodes when the native decoder cannot scale to appropriately match the sampleSize
+// (for example, RAW). If the sampleSize divides evenly into the dimension, we require that the
+// scale matches exactly. If sampleSize does not divide evenly, we allow the decoder to choose how
+// best to round.
+static bool needsFineScale(const int fullSize, const int decodedSize, const int sampleSize) {
+ if (fullSize % sampleSize == 0 && fullSize / sampleSize != decodedSize) {
+ return true;
+ } else if ((fullSize / sampleSize + 1) != decodedSize &&
+ (fullSize / sampleSize) != decodedSize) {
+ return true;
+ }
+ return false;
+}
+
+static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize,
+ const int sampleSize) {
+ return needsFineScale(fullSize.width(), decodedSize.width(), sampleSize) ||
+ needsFineScale(fullSize.height(), decodedSize.height(), sampleSize);
+}
+
static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {
// This function takes ownership of the input stream. Since the SkAndroidCodec
// will take ownership of the stream, we don't necessarily need to take ownership
@@ -250,7 +270,6 @@
}
}
}
- const bool willScale = scale != 1.0f;
// Create the codec.
NinePatchPeeker peeker;
@@ -269,15 +288,28 @@
prefColorType = kN32_SkColorType;
}
- // Determine the output size and return if the client only wants the size.
+ // Determine the output size.
SkISize size = codec->getSampledDimensions(sampleSize);
+
+ int scaledWidth = size.width();
+ int scaledHeight = size.height();
+ bool willScale = false;
+
+ // Apply a fine scaling step if necessary.
+ if (needsFineScale(codec->getInfo().dimensions(), size, sampleSize)) {
+ willScale = true;
+ scaledWidth = codec->getInfo().width() / sampleSize;
+ scaledHeight = codec->getInfo().height() / sampleSize;
+ }
+
+ // Set the options and return if the client only wants the size.
if (options != NULL) {
jstring mimeType = encodedFormatToString(env, codec->getEncodedFormat());
if (env->ExceptionCheck()) {
return nullObjectReturn("OOM in encodedFormatToString()");
}
- env->SetIntField(options, gOptions_widthFieldID, size.width());
- env->SetIntField(options, gOptions_heightFieldID, size.height());
+ env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
+ env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
env->SetObjectField(options, gOptions_mimeFieldID, mimeType);
if (onlyDecodeSize) {
@@ -285,6 +317,13 @@
}
}
+ // Scale is necessary due to density differences.
+ if (scale != 1.0f) {
+ willScale = true;
+ scaledWidth = static_cast<int>(scaledWidth * scale + 0.5f);
+ scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f);
+ }
+
android::Bitmap* reuseBitmap = nullptr;
unsigned int existingBufferSize = 0;
if (javaBitmap != NULL) {
@@ -381,13 +420,6 @@
return nullObjectReturn("codec->getAndroidPixels() failed.");
}
- int scaledWidth = size.width();
- int scaledHeight = size.height();
- if (willScale) {
- scaledWidth = int(scaledWidth * scale + 0.5f);
- scaledHeight = int(scaledHeight * scale + 0.5f);
- }
-
jbyteArray ninePatchChunk = NULL;
if (peeker.mPatch != NULL) {
if (willScale) {
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index ee8fb19..f7a5e8a 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "Process"
+// To make sure cpu_set_t is included from sched.h
+#define _GNU_SOURCE 1
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -288,6 +290,139 @@
return (int) sp;
}
+#ifdef ENABLE_CPUSETS
+/** Sample CPUset list format:
+ * 0-3,4,6-8
+ */
+static void parse_cpuset_cpus(char *cpus, cpu_set_t *cpu_set) {
+ unsigned int start, end, matched, i;
+ char *cpu_range = strtok(cpus, ",");
+ while (cpu_range != NULL) {
+ start = end = 0;
+ matched = sscanf(cpu_range, "%u-%u", &start, &end);
+ cpu_range = strtok(NULL, ",");
+ if (start >= CPU_SETSIZE) {
+ ALOGE("parse_cpuset_cpus: ignoring CPU number larger than %d.", CPU_SETSIZE);
+ continue;
+ } else if (end >= CPU_SETSIZE) {
+ ALOGE("parse_cpuset_cpus: ignoring CPU numbers larger than %d.", CPU_SETSIZE);
+ end = CPU_SETSIZE - 1;
+ }
+ if (matched == 1) {
+ CPU_SET(start, cpu_set);
+ } else if (matched == 2) {
+ for (i = start; i <= end; i++) {
+ CPU_SET(i, cpu_set);
+ }
+ } else {
+ ALOGE("Failed to match cpus");
+ }
+ }
+ return;
+}
+
+/**
+ * Stores the CPUs assigned to the cpuset corresponding to the
+ * SchedPolicy in the passed in cpu_set.
+ */
+static void get_cpuset_cores_for_policy(SchedPolicy policy, cpu_set_t *cpu_set)
+{
+ FILE *file;
+ const char *filename;
+
+ CPU_ZERO(cpu_set);
+
+ switch (policy) {
+ case SP_BACKGROUND:
+ filename = "/dev/cpuset/background/cpus";
+ break;
+ case SP_FOREGROUND:
+ case SP_AUDIO_APP:
+ case SP_AUDIO_SYS:
+ filename = "/dev/cpuset/foreground/cpus";
+ break;
+ case SP_TOP_APP:
+ filename = "/dev/cpuset/top-app/cpus";
+ break;
+ default:
+ filename = NULL;
+ }
+
+ if (!filename) return;
+
+ file = fopen(filename, "re");
+ if (file != NULL) {
+ // Parse cpus string
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t num_read = getline(&line, &len, file);
+ fclose (file);
+ if (num_read > 0) {
+ parse_cpuset_cpus(line, cpu_set);
+ } else {
+ ALOGE("Failed to read %s", filename);
+ }
+ free(line);
+ }
+ return;
+}
+#endif
+
+
+/**
+ * Determine CPU cores exclusively assigned to the
+ * cpuset corresponding to the SchedPolicy and store
+ * them in the passed in cpu_set_t
+ */
+void get_exclusive_cpuset_cores(SchedPolicy policy, cpu_set_t *cpu_set) {
+#ifdef ENABLE_CPUSETS
+ int i;
+ cpu_set_t tmp_set;
+ get_cpuset_cores_for_policy(policy, cpu_set);
+ for (i = 0; i < SP_CNT; i++) {
+ if ((SchedPolicy) i == policy) continue;
+ get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set);
+ // First get cores exclusive to one set or the other
+ CPU_XOR(&tmp_set, cpu_set, &tmp_set);
+ // Then get the ones only in cpu_set
+ CPU_AND(cpu_set, cpu_set, &tmp_set);
+ }
+#else
+ (void) policy;
+ CPU_ZERO(cpu_set);
+#endif
+ return;
+}
+
+jintArray android_os_Process_getExclusiveCores(JNIEnv* env, jobject clazz) {
+ SchedPolicy sp;
+ cpu_set_t cpu_set;
+ jintArray cpus;
+ int pid = getpid();
+ if (get_sched_policy(pid, &sp) != 0) {
+ signalExceptionForGroupError(env, errno);
+ return NULL;
+ }
+ get_exclusive_cpuset_cores(sp, &cpu_set);
+ int num_cpus = CPU_COUNT(&cpu_set);
+ cpus = env->NewIntArray(num_cpus);
+ if (cpus == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return NULL;
+ }
+
+ jint* cpu_elements = env->GetIntArrayElements(cpus, 0);
+ int count = 0;
+ for (int i = 0; i < CPU_SETSIZE && count < num_cpus; i++) {
+ if (CPU_ISSET(i, &cpu_set)) {
+ cpu_elements[count++] = i;
+ }
+ }
+
+ env->ReleaseIntArrayElements(cpus, cpu_elements, 0);
+ return cpus;
+}
+
static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, jboolean bgOk) {
// Establishes the calling thread as illegal to put into the background.
// Typically used only for the system process's main looper.
@@ -1053,6 +1188,7 @@
{"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup},
{"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup},
{"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup},
+ {"getExclusiveCores", "()[I", (void*)android_os_Process_getExclusiveCores},
{"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness},
{"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
{"setUid", "(I)I", (void*)android_os_Process_setUid},
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 10cdae8..666e1e7 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Stembystand"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Sluit nou"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud versteek"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhoud word versteek volgens beleid"</string>
<string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Raak vir meer opsies."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-ontfouter gekoppel"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Raak om USB-ontfouting te deaktiveer."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Neem tans foutverslag …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deel foutverslag?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deel tans foutverslag …"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Jou IT-administrateur het \'n foutverslag versoek om met die foutsporing van hierdie toestel te help. Programme en data sal dalk gedeel word."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEEL"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"WEIER"</string>
<string name="select_input_method" msgid="8547250819326693584">"Verander sleutelbord"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Kies sleutelborde"</string>
<string name="show_ime" msgid="2506087537466597099">"Hou dit op die skerm terwyl fisieke sleutelbord aktief is"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Muurpapier"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Verander muurpapier"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Kennisgewingluisteraar"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-luisteraar"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Toestandverskaffer"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Kennisgewingassistent"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN geaktiveer"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is geaktiveer deur <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Raak om die netwerk te bestuur."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Ontspeld"</string>
<string name="app_info" msgid="6856026610594615344">"Programinligting"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 1fb3c51..e32562c 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"የድምጽ እርዳታ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"አሁን ቆልፍ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"ይዘቶች ተደብቀዋል"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ይዘቶች በመመሪያ ተደብቀዋል"</string>
<string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ለተጨማሪ አማራጮች ነካ ያድርጉ።"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB አድስ ተያይዟል"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ማረሚያ ላለማንቃት ዳስስ።"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"የሳንካ ሪፖርትን በመውሰድ ላይ…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"የሳንካ ሪፖርት ይጋራ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"የሳንካ ሪፖርትን በማጋራት ላይ…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"የእርስዎ አይቲ አስተዳዳሪ ለዚህ መሣሪያ መላ ለመፈለግ የሳንካ ሪፖርት ጠይቀዋል። መተግበሪያዎች እና ውሂብ ሊጋሩ ይችላሉ።"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"አጋራ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"አትቀበል"</string>
<string name="select_input_method" msgid="8547250819326693584">"ቁልፍ ሰሌዳ ይቀይሩ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ቁልፍ ሰሌዳዎችን ምረጥ"</string>
<string name="show_ime" msgid="2506087537466597099">"አካላዊ የቁልፍ ሰሌዳ ገቢር ሆኖ ሳለ በማያ ገጽ ላይ አቆየው"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ልጣፍ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ልጣፍ ለውጥ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ማሳወቂያ አዳማጭ"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"የምናባዊ እውነታ አዳማጭ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"የሁኔታ አቅራቢ"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"የማሳወቂያ ረዳት"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN ነቅቷል።"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN በ<xliff:g id="APP">%s</xliff:g>ገብሯል"</string>
<string name="vpn_text" msgid="3011306607126450322">"አውታረመረብ ለማደራጀት ንካ።"</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"ንቀል"</string>
<string name="app_info" msgid="6856026610594615344">"የመተግበሪያ መረጃ"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 518edab..06e0047 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -237,7 +237,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"المساعد الصوتي"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"قفل الآن"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"تم إخفاء المحتويات بواسطة السياسة"</string>
<string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
@@ -1168,8 +1167,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"الخلفية"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"برنامج تلقّي الإشعارات الصوتية"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"مستمع واقع افتراضي"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"موفر الحالة"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"مساعد الإشعار"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"تم تنشيط الشبكة الظاهرية الخاصة (VPN)"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"تم تنشيط VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"المس لإدارة الشبكة."</string>
@@ -1640,4 +1641,8 @@
<string name="unpin_target" msgid="3556545602439143442">"إزالة تثبيت"</string>
<string name="app_info" msgid="6856026610594615344">"معلومات عن التطبيق"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index d155182..bd4d4b9 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Səs Yardımçısı"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"İndi kilidləyin"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Məzmun gizlidir"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Məzmun siyasət tərəfindən gizlədilib"</string>
<string name="safeMode" msgid="2788228061547930246">"Təhlükəsiz rejim"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Əlavə seçimlər üçün toxunun."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB sazlama qoşuludur"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB debaqı deaktivasiya etmək üçün toxunun."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Baq hesabat verilir..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Baq hesabatı paylaşılsın?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Baq hesabatı paylaşılır..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT admininiz bu cihazda nasazlıqların aşkarlanması üçün baq hesabatı sorğusu göndərdi. Tətbiqlər və data paylaşıla bilər."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PAYLAŞIN"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RƏDD ET"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturanı dəyişin"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Klaviaturaları seçin"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziki klaviatura aktiv olduğu halda ekranda saxlayın"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Divar kağızı"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Divar kağızını dəyişin"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildiriş dinləyən"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR dinləyici"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Şərait provayderi"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Bildiriş köməkçisi"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN aktivləşdirildi"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> tərəfindən aktivləşdirilib"</string>
<string name="vpn_text" msgid="3011306607126450322">"Şəbəkəni idarə etmək üçün toxunun."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Çıxarın"</string>
<string name="app_info" msgid="6856026610594615344">"Tətbiq məlumatı"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 12ae1b0..1fc8308 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -231,7 +231,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj odmah"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je sakriven"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je sakriven smernicama"</string>
<string name="safeMode" msgid="2788228061547930246">"Bezbedni režim"</string>
@@ -1060,16 +1059,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za još opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je uspostavljeno"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izveštaj o grešci se generiše…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li da podelite izveštaj o grešci?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deli se izveštaj o grešci…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT administrator je zatražio izveštaj o grešci radi lakšeg rešavanja problema u vezi sa ovim uređajem. Aplikacije i podaci mogu da se dele."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELI"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Izaberite tastature"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadrži ga na ekranu dok je fizička tastatura aktivna"</string>
@@ -1148,8 +1143,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadina"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Promena pozadine"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Monitor obaveštenja"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Obrađivač za virtuelnu realnost"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Dobavljač uslova"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomoćnik za obaveštenja"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN je aktiviran"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> je aktivirala VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dodirnite da biste upravljali mrežom."</string>
@@ -1587,4 +1584,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Otkači"</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 9cdd298..0ac8829 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Гласова помощ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Заключване сега"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Скрито съдържание"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Съдържанието е скрито чрез правило"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Докоснете за още опции."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отстраняване на грешки през USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Докоснете за деактивиране"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Сигналът за програмна грешка се извлича…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели ли сигналът за програмна грешка?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Сигналът за програмна грешка се споделя…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Системният ви администратор поиска сигнал за програмна грешка с цел отстраняване на неизправностите на това устройство. Възможно е да бъдат споделени приложения и данни."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"СПОДЕЛЯНЕ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОТХВЪРЛЯНЕ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Промяна на клавиатурата"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Избиране на клавиатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Показване на екрана, докато физическата клавиатура е активна"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известия"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Доставчик на условия"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помощник за известия"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN е активирана"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана от <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Докоснете за управление на мрежата."</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Освобождаване"</string>
<string name="app_info" msgid="6856026610594615344">"Информация за приложението"</string>
<string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index a598d3b..925a9d0 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ভয়েস সহায়তা"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"এখনই লক করুন"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"৯৯৯+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>টি)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"লুকানো বিষয়বস্তু"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"নীতির কারণে সামগ্রী লুকানো আছে"</string>
<string name="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"আরো বিকল্পের জন্য স্পর্শ করুন৷"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ডিবাগিং সংযুক্ত হয়েছে"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ডিবাগিং অক্ষম করতে স্পর্শ করুন৷"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ত্রুটির প্রতিবেদন নেওয়া হচ্ছে..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ত্রুটির প্রতিবেদন শেয়ার করবেন?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ত্রুটির প্রতিবেদন শেয়ার করা হচ্ছে..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"আপনার আইটি প্রশাসক এই ডিভাইসটির সমস্যা নিবারণে সহায়তা করতে একটি ত্রুটির প্রতিবেদন চেয়েছেন৷ অ্যাপ্লিকেশান এবং ডেটা শেয়ার করা হতে পারে৷"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"শেয়ার করুন"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"অস্বীকার করুন"</string>
<string name="select_input_method" msgid="8547250819326693584">"কীবোর্ড পরিবর্তন করুন"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"কীবোর্ড চয়ন করুন"</string>
<string name="show_ime" msgid="2506087537466597099">"ফিজিক্যাল কীবোর্ড সক্রিয় থাকার সময় এটিকে স্ক্রীনে রাখুন"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ওয়ালপেপার"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ওয়ালপেপার পরিবর্তন করুন"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"বিজ্ঞপ্তির শ্রোতা"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR শ্রোতা"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"শর্ত প্রদানকারী"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"বিজ্ঞপ্তি সহায়ক"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN সক্রিয়"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> এর দ্বারা VPN সক্রিয় করা হয়েছে"</string>
<string name="vpn_text" msgid="3011306607126450322">"নেটওয়ার্ক পরিচালনা করতে স্পর্শ করুন৷"</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"আনপিন করুন"</string>
<string name="app_info" msgid="6856026610594615344">"অ্যাপ্লিকেশানের তথ্য"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index 61ea35c..eea3d58 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -231,7 +231,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj odmah"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je sakriven"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj skriven u skladu sa pravilima"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
@@ -1060,16 +1059,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za više opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Uređaj za USB otklanjanje grešaka povezan"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili USB otklanjanje grešaka."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Prijem izvještaja o grešci..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Podijeliti izvještaj o grešci?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvještaja o grešci..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Vaš IT administrator je zatražio izvještaj o grešci kako bi pomogao u rješavanju problema ovog uređaja. Aplikacije i podaci se mogu dijeliti."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PODIJELI"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBACI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promijeni tastaturu"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Odaberite tastature"</string>
<string name="show_ime" msgid="2506087537466597099">"Prikaži na ekranu dok je fizička tastatura aktivna"</string>
@@ -1148,8 +1143,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadinska slika"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Promijenite pozadinsku sliku"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Usluga za praćenje obavještenja"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR slušalac"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Pružalac uslova"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomoćnik za obavještenja"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> je aktivirala VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
@@ -1587,4 +1584,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Otkači"</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 3c32e9a..39346b8 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. per veu"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloqueja ara"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contingut amagat"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contingut amagat de conformitat amb la política"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca per veure més opcions."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuració USB activada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca per desactivar la depuració USB"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"S\'està creant l\'informe d\'errors…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vols compartir l\'informe d\'errors?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"S\'està compartint l\'informe d\'errors…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"L\'administrador de TI ha sol·licitat un informe d\'errors per resoldre els problemes d\'aquest dispositiu. És possible que es comparteixin aplicacions i dades."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTEIX"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REBUTJA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Canvia el teclat"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Tria els teclats"</string>
<string name="show_ime" msgid="2506087537466597099">"El deixa a la pantalla mentre el teclat físic està actiu"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fons de pantalla"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Canvia el fons de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Oient de notificacions"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Processador de realitat virtual"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveïdor de condicions"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistent de notificacions"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ha activat VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca per gestionar la xarxa."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"No fixis"</string>
<string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string>
<string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 9d3ecff..f96dfa9 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -233,7 +233,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Hlas. asistence"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zamknout"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah skrytý zásadami"</string>
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
@@ -1068,16 +1067,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Klepnutím zobrazíte další možnosti."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes USB připojeno"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotykem zakážete ladění USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Vytváření zprávy o chybě…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Sdílet zprávu o chybě?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Sdílení zprávy o chybě…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administrátor IT si vyžádal zprávu o chybě, aby mohl problém odstranit. Aplikace a data mohou být sdílena."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SDÍLET"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODMÍTNOUT"</string>
<string name="select_input_method" msgid="8547250819326693584">"Změna klávesnice"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vybrat klávesnici"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechat na obrazovce, když je aktivní fyzická klávesnice"</string>
@@ -1156,8 +1151,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Změnit tapetu"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikace poslouchající oznámení"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovatel podmínky"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent oznámení"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"Síť VPN je aktivována"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikace <xliff:g id="APP">%s</xliff:g> aktivovala síť VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotykem zobrazíte správu sítě."</string>
@@ -1606,4 +1604,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Odepnout"</string>
<string name="app_info" msgid="6856026610594615344">"Informace o aplikaci"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 2ee9afd..47ca429 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Taleassistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Indholdet er skjult"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Indholdet er skjult af politikken"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Tryk for at se flere muligheder."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-fejlretning er tilsluttet"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tryk for at deaktivere USB-fejlretning."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Opretter fejlrapport…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele fejlrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler fejlrapport…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Din it-administrator har anmodet om en fejlrapport for bedre at kunne finde og rette fejlen på enheden. Apps og data deles muligvis."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEL"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AFVIS"</string>
<string name="select_input_method" msgid="8547250819326693584">"Skift tastatur"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vælg tastaturer"</string>
<string name="show_ime" msgid="2506087537466597099">"Behold den på skærmen, mens det fysiske tastatur er aktivt"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Baggrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tjeneste til formidling af betingelser"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Underretningsassistent"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN er aktiveret."</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tryk for at administrere netværket."</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Frigør"</string>
<string name="app_info" msgid="6856026610594615344">"Oplysninger om appen"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index c9874b8..d04d6b6 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Sprachassistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Jetzt sperren"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Inhalte ausgeblendet"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Inhalte aufgrund der Richtlinien ausgeblendet"</string>
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Für weitere Optionen tippen"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Zum Deaktivieren berühren"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Fehlerbericht wird aufgerufen…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Fehlerbericht teilen?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Fehlerbericht wird geteilt…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Dein IT-Administrator hat einen Fehlerbericht zur Fehlerbehebung für dieses Gerät angefordert. Apps und Daten werden unter Umständen geteilt."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"TEILEN"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ABLEHNEN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tastatur ändern"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Tastatur auswählen"</string>
<string name="show_ime" msgid="2506087537466597099">"Auf dem Display einblenden, wenn die physische Tastatur aktiv ist"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Hintergrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Hintergrund ändern"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Benachrichtigungs-Listener"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-Listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Bedingungsprovider"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Benachrichtigungsassistent"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviert"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN wurde von <xliff:g id="APP">%s</xliff:g> aktiviert."</string>
<string name="vpn_text" msgid="3011306607126450322">"Zum Verwalten des Netzwerks berühren"</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Markierung entfernen"</string>
<string name="app_info" msgid="6856026610594615344">"App-Informationen"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 1cac5e5..b39d8d8 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Φων.υποβοηθ."</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Κλείδωμα τώρα"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Κρυφό περιεχόμενο"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Το περιεχόμενο είναι κρυφό βάσει πολιτικής"</string>
<string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Αγγίξτε για περισσότερες επιλογές."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Απεν. του εντοπ. σφαλμάτων USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Λήψη αναφοράς σφάλματος…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Κοινή χρήση αναφοράς σφάλματος;"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Κοινή χρήση αναφοράς σφάλματος…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Ο διαχειριστής IT σας ζήτησε μια αναφορά σφάλματος για να συμβάλει στην αντιμετώπιση του προβλήματος αυτής της συσκευής. Ενδέχεται να κοινοποιηθούν οι εφαρμογές και τα δεδομένα."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ΚΟΙΝΟΠΟΙΗΣΗ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ΑΠΟΡΡΙΨΗ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Αλλαγή πληκτρολογίου"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Επιλογή πληκτρολογίων"</string>
<string name="show_ime" msgid="2506087537466597099">"Να παραμένει στην οθόνη όταν είναι ενεργό το φυσικό πληκτρολόγιο"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ταπετσαρία"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Υπηρεσία ακρόασης ειδοποίησης"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Λειτουργία ακρόασης Εικονικής Πραγματικότητας"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Πάροχος συνθηκών"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Βοηθός ειδοποιήσεων"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"Το VPN ενεργοποιήθηκε"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Το VPN ενεργοποιήθηκε από την εφαρμογή <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Αγγίξτε για τη διαχείριση του δικτύου."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Ξεκαρφίτσωμα"</string>
<string name="app_info" msgid="6856026610594615344">"Πληροφορίες εφαρμογής"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index a6c0e65..21c502e 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -1136,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
@@ -1564,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a6c0e65..21c502e 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -1136,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
@@ -1564,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index a6c0e65..21c502e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contents hidden by policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -1136,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
@@ -1564,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
<string name="app_info" msgid="6856026610594615344">"App info"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index e389a22..c84970f 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenido oculto debido a la política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca para ver más opciones."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración por USB conectada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para desactivar la depuración por USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Realizando un informe de errores…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"El administrador de TI solicitó un informe de errores para solucionar los problemas de este dispositivo. Es posible que se compartan apps y datos."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECHAZAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar el teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Seleccionar teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Mantener en la pantalla cuando el teclado físico está activo"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Papel tapiz"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Agente de escucha de notificaciones"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Procesador de realidad virtual"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveedor de condiciones"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistente de notificaciones"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"No fijar"</string>
<string name="app_info" msgid="6856026610594615344">"Información de la app"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c4d1ffd..3e220fe 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"> 999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenidos ocultos por política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -276,7 +275,7 @@
<string name="permdesc_install_shortcut" msgid="8341295916286736996">"Permite que una aplicación añada accesos directos a la pantalla de inicio sin intervención del usuario."</string>
<string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"desinstalar accesos directos"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Permite que la aplicación elimine accesos directos de la pantalla de inicio sin la intervención del usuario."</string>
- <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redireccionar llamadas salientes"</string>
+ <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirigir llamadas salientes"</string>
<string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite que la aplicación vea el número que se marca al realizar una llamada con la opción de redirigir la llamada a otro número o cancelar la llamada."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"recibir mensajes de texto (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite que la aplicación reciba y procese mensajes MMS, lo que significa que podría utilizar este permiso para controlar o eliminar mensajes enviados al dispositivo sin mostrárselos al usuario."</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca para obtener más opciones"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB habilitada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca aquí para inhabilitarla"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Creando informe de errores…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"¿Compartir informe de errores?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartiendo informe de errores…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Tu administrador de TI ha solicitado un informe de errores para solucionar problemas de este dispositivo. Es posible que se compartan las aplicaciones y los datos."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECHAZAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Elegir teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Debe seguir en pantalla mientras el teclado físico esté activo"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fondo de pantalla"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Detector de notificaciones"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Procesador de Realidad Virtual"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveedor de condiciones"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistente de notificaciones"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
@@ -1572,4 +1569,8 @@
<string name="unpin_target" msgid="3556545602439143442">"No fijar"</string>
<string name="app_info" msgid="6856026610594615344">"Información de la aplicación"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index f2faf00..dd08800 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Häälabi"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lukusta kohe"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Sisu on peidetud"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisu on eeskirjadega peidetud"</string>
<string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Puudutage rohkemate valikute kuvamiseks."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-silumine ühendatud"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Puudutage USB-silumise keelamiseks."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Veaaruande võtmine …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kas jagada veaaruannet?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Veaaruande jagamine …"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT-administraator taotles veaaruannet, mis aitaks seadmes vigu otsida. Rakendusi ja andmeid võidakse jagada."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"JAGA"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"KEELDU"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviatuuri muutmine"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vali klaviatuurid"</string>
<string name="show_ime" msgid="2506087537466597099">"Hoia seda ekraanil, kui füüsiline klaviatuur on aktiivne"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustapilt"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Muutke taustapilti"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Märguannete kuulamisteenus"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Virtuaalreaalses režiimis kuulaja"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tingimuse pakkuja"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Märguannete abi"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN on aktiveeritud"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Vabasta"</string>
<string name="app_info" msgid="6856026610594615344">"Rakenduse teave"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index a24831a..1811edb 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ahots-laguntza"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Blokeatu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Edukiak ezkutatuta daude"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Gidalerro batzuk ezkutatu dira, gidalerroei jarraiki"</string>
<string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Ukitu aukera gehiago ikusteko."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB arazketa konektatuta"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB arazketa desgaitzeko, ukitu hau."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Akatsen txostena sortzen…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Akatsen txostena partekatu nahi duzu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Akatsen txostena partekatzen…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IKT administratzaileak akatsen txostena eskatu du gailuko arazoa konpontzeko. Baliteke aplikazioak eta datuak partekatzea."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTEKATU"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"BAZTERTU"</string>
<string name="select_input_method" msgid="8547250819326693584">"Aldatu teklatua"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Aukeratu teklatuak"</string>
<string name="show_ime" msgid="2506087537466597099">"Erakutsi pantailan teklatu fisikoa aktibo dagoen bitartean"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Horma-papera"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Aldatu horma-papera"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Jakinarazpenak hautemateko zerbitzua"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Errealitate birtualeko hautemailea"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Baldintza-hornitzailea"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Jakinarazpenen laguntzailea"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN eginbidea aktibatuta"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> aplikazioak VPN konexioa aktibatu du"</string>
<string name="vpn_text" msgid="3011306607126450322">"Ukitu sarea kudeatzeko."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Kendu aingura"</string>
<string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 17a5f5b..4e801cc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"دستیار صوتی"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"اکنون قفل شود"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"محتوا بر اساس خطمشی پنهان شده است"</string>
<string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"برای گزینههای بیشتر لمس کنید."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"اشکالزدایی USB متصل شد"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"غیرفعالکردن اشکالزداییUSB: با لمس آن."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"درحال گرفتن گزارش اشکال…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"گزارش اشکال به اشتراک گذاشته شود؟"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"درحال اشتراکگذاری گزارش اشکال…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"سرپرست فناوری اطلاعات شما برای کمک به عیبیابی این دستگاه، گزارش اشکال درخواست کرده است. ممکن است برنامهها و دادهها به اشتراک گذاشته شوند."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"اشتراکگذاری"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"نپذیرفتن"</string>
<string name="select_input_method" msgid="8547250819326693584">"تغییر صفحهکلید"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"انتخاب صفحهکلیدها"</string>
<string name="show_ime" msgid="2506087537466597099">"وقتی صفحهکلید فیزیکی فعال است این ویرایشگر را روی صفحه نگهمیدارد"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"کاغذدیواری"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر کاغذدیواری"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"شنونده اعلان"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"شنونده VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ارائهدهنده وضعیت"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"دستیار اعلان"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN فعال شد"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN توسط <xliff:g id="APP">%s</xliff:g> فعال شده است"</string>
<string name="vpn_text" msgid="3011306607126450322">"برای مدیریت شبکه لمس کنید."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"برداشتن پین"</string>
<string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 15cba76b..300328b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ääniapuri"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lukitse nyt"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Sisältö piilotettu"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sisältö on piilotettu käytännön perusteella."</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Lisää vaihtoehtoja koskettamalla"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-vianetsintä yhdistetty"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sulje USB-vianetsintä koskettamalla."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Luodaan virheraporttia…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Jaetaanko virheraportti?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Jaetaan virheraporttia…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Järjestelmänvalvoja pyysi virheraporttia voidakseen auttaa laitteen vianetsinnässä. Sovelluksia ja tietoja voidaan jakaa."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"JAA"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"HYLKÄÄ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Vaihda näppäimistö"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Valitse näppäimistöt"</string>
<string name="show_ime" msgid="2506087537466597099">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen."</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustakuva"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Vaihda taustakuvaa"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ilmoituskuuntelija"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Virtuaalitodellisuuden kuuntelija"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ehtojen toimituspalvelu"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ilmoitusapuri"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN on aktivoitu"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> on aktivoinut VPN-yhteyden"</string>
<string name="vpn_text" msgid="3011306607126450322">"Voit hallinnoida verkkoa koskettamalla."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Irrota"</string>
<string name="app_info" msgid="6856026610594615344">"Sovelluksen tiedot"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 83e7936..6688060 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. vocale"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux politiques"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Touchez pour afficher plus d\'options."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Appuyez pour désactiver le débogage USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Création d\'un rapport de bogue en cours..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bogue?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bogue en cours..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Votre administrateur informatique a demandé un rapport de bogue pour l\'aider à dépanner cet appareil. Les applications et les données peuvent être partagées."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTAGER"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUSER"</string>
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Choisir les claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fond d\'écran"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Outil d\'écoute des notifications"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Écouteur de réalité virtuelle"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fournisseur de conditions"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistant des notifications"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Annuler l\'épinglage"</string>
<string name="app_info" msgid="6856026610594615344">"Détails de l\'application"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 2e047ad..097a8a1 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Assistance vocale"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenu masqué conformément aux règles"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Appuyez pour afficher plus d\'options"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Appuyez pour désact. débogage USB"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Création du rapport de bug…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Partager le rapport de bug ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Partage du rapport de bug…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Votre administrateur informatique a demandé un rapport de bug pour l\'aider à résoudre le problème lié à cet appareil. Il est possible que des applications et des données soient partagées."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTAGER"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUSER"</string>
<string name="select_input_method" msgid="8547250819326693584">"Changer de clavier"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Sélectionner des claviers"</string>
<string name="show_ime" msgid="2506087537466597099">"Afficher lorsque le clavier physique est activé"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fond d\'écran"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Outil d\'écoute des notifications"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Écouteur de réalité virtuelle"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fournisseur de conditions"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistant de notifications"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Retirer"</string>
<string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string>
<string name="negative_duration" msgid="5688706061127375131">"− <xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index e721037..fb98b76c 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asistente voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contido oculto"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Ocultouse contido por causa da política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toca para ver máis opcións."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB conectada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca aquí para desactivala"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Creando informe de erros…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Queres compartir o informe de erros?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartindo informe de erros..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"O teu administrador de TI solicitou un informe de erros para axudar a solucionar os problemas deste dispositivo. É posible que se compartan aplicacións e datos."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ANULAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Seleccionar teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manteno na pantalla mentres o teclado físico estea activo"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fondo de pantalla"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Axente de escoita de notificacións"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Axente de escoita de RV"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condicións"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistente de notificacións"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> activou a VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca aquí para xestionar a rede."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Soltar"</string>
<string name="app_info" msgid="6856026610594615344">"Información da aplicación"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 6b05537..1fa64bc 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"વૉઇસ સહાય"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"હવે લૉક કરો"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"સામગ્રીઓ છુપાવેલ છે"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"નીતિ દ્વારા સામગ્રી છુપાવાઈ"</string>
<string name="safeMode" msgid="2788228061547930246">"સુરક્ષિત મોડ"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"વધુ વિકલ્પો માટે ટચ કરો."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ડીબગિંગ કનેક્ટ થયું."</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ડીબગિંગ અક્ષમ કરવા માટે ટચ કરો."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"બગ રિપોર્ટ લઈ રહ્યાં છે…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"બગ રિપોર્ટ શેર કરીએ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"બગ રિપોર્ટ શેર કરી રહ્યાં છે…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"તમારા IT વ્યવસ્થાપક એ આ ઉપકરણની સમસ્યા નિવારણમાં સહાય માટે બગ રિપોર્ટની વિનંતી કરી છે. ઍપ્લિકેશનો અને ડેટા શેર કરવામાં આવી શકે છે."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"શેર કરો"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"નકારો"</string>
<string name="select_input_method" msgid="8547250819326693584">"કીબોર્ડ બદલો"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"કીબોર્ડ્સ પસંદ કરો"</string>
<string name="show_ime" msgid="2506087537466597099">"જ્યારે ભૌતિક કીબોર્ડ સક્રિય હોય ત્યારે તેને સ્ક્રીન પર રાખો"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"વૉલપેપર"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"વૉલપેપર બદલો"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"સૂચના સાંભળનાર"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR સાંભળનાર"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"શરત પ્રદાતા"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"સૂચના સહાયક"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN સક્રિય કર્યું"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> દ્વારા VPN સક્રિય થયું"</string>
<string name="vpn_text" msgid="3011306607126450322">"નેટવર્કને સંચાલિત કરવા માટે ટચ કરો."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"અનપિન કરો"</string>
<string name="app_info" msgid="6856026610594615344">"ઍપ્લિકેશન માહિતી"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 6c55445..fbd50ed 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"वॉइस सहायक"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"अभी लॉक करें"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"छिपी हुई सामग्री"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"सामग्री पॉलिसी के द्वारा छिपी हुई है"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"और विकल्पों के लिए स्पर्श करें."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग कनेक्ट किया गया"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करना अक्षम करने के लिए स्पर्श करें."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट प्राप्त की जा रही है…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्ट साझा करें?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्ट साझा की जा रही है…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"आपके आईटी व्यवस्थापक ने इस डिवाइस के समस्या निवारण में सहायता के लिए एक बग रिपोर्ट का अनुरोध किया है. ऐप्स और डेटा को साझा किया जा सकता है."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझा करें"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार करें"</string>
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदलें"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड चुनें"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड के सक्रिय होने के दौरान इसे स्क्रीन पर बनाए रखें"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"नोटिफिकेशन श्रवणकर्ता"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR श्रोता"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"स्थिति प्रदाता"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"नोटिफिकेशन सहायक"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN को <xliff:g id="APP">%s</xliff:g> द्वारा सक्रिय किया गया है"</string>
<string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबंधित करने के लिए स्पर्श करें."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"अनपिन करें"</string>
<string name="app_info" msgid="6856026610594615344">"ऐप की जानकारी"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index c32c5ee..d396c07 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -231,7 +231,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj sada"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je skriven"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Sadržaj je skriven prema pravilima"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
@@ -1060,16 +1059,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za više opcija."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Priključen je alat za uklanjanje pogrešaka USB-om"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da se onemogući otklanjanje pogrešaka USB-om."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izrada izvješća o programskoj pogrešci…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li podijeliti izvješće o programskoj pogrešci?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvješća o programskoj pogrešci…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT administrator zatražio je izvješće o programskoj pogrešci radi lakšeg rješavanja problema na uređaju. Moguće je da će se aplikacije i podaci dijeliti."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DIJELI"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODBIJ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Promjena tipkovnice"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Odaberi tipkovnice"</string>
<string name="show_ime" msgid="2506087537466597099">"Zadržava se na zaslonu dok je fizička tipkovnica aktivna"</string>
@@ -1148,8 +1143,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadinska slika"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Promjena pozadinske slike"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Slušatelj obavijesti"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Slušatelj virtualne stvarnosti"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Davatalj uvjeta"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomoćnik za obavijesti"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> aktivirala je VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
@@ -1587,4 +1584,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Otkvači"</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 91f5280..987d1f9 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Hangsegéd"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zárolás most"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Tartalom elrejtve"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"A tartalom irányelv miatt elrejtve"</string>
<string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Érintse meg a további lehetőségekhez."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB hibakereső csatlakoztatva"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Érintse meg az USB hibakeresés kikapcsolásához."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Hibajelentés készítése…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Megosztja a hibajelentést?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hibajelentés megosztása…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"A rendszergazda hibajelentést kért, hogy segíthessen az eszközzel kapcsolatos probléma megoldásában. Előfordulhat, hogy a rendszer megosztja az alkalmazásokat és adatokat."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"MEGOSZTÁS"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ELUTASÍTÁS"</string>
<string name="select_input_method" msgid="8547250819326693584">"Billentyűzet megváltoztatása"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Billentyűzetek kiválasztása"</string>
<string name="show_ime" msgid="2506087537466597099">"Maradjon a képernyőn, amíg a billentyűzet aktív"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Háttérkép"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Háttérkép megváltoztatása"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Értesítésfigyelő"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Virtuálisvalóság-figyelő"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Feltételbiztosító"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Értesítési segéd"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN aktiválva"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A(z) <xliff:g id="APP">%s</xliff:g> aktiválta a VPN-t"</string>
<string name="vpn_text" msgid="3011306607126450322">"Érintse meg a hálózat kezeléséhez."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Feloldás"</string>
<string name="app_info" msgid="6856026610594615344">"Alkalmazásinformáció"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index f009c7b..f02b9dd 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ձայնային օգնութ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Կողպել հիմա"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Բովանդակությունը թաքցված է"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Բովանդակությունը թաքցվել է ըստ քաղաքականության"</string>
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Հպեք՝ լրացուցիչ ընտրանքների համար:"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB վրիպազերծումը միացված է"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Հպեք` USB կարգաբերումը կասեցնելու համար:"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Վրիպակի զեկույցի ստեղծում…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Տրամադրե՞լ վրիպակի զեկույցը:"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Վրիպակի զեկույցի տրամադրում…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Այս սարքի անսարքությունների վերացման նպատակով ձեր ՏՏ ադմինիստրատորին անհրաժեշտ է վրիպակի զեկույց: Կարող են տրամադրվել տեղեկություններ ձեր հավելվածների մասին և այլ տվյալներ:"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ՏՐԱՄԱԴՐԵԼ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ՄԵՐԺԵԼ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Փոխել ստեղնաշարը"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Ընտրել ստեղնաշար"</string>
<string name="show_ime" msgid="2506087537466597099">"Պահել էկրանին մինչդեռ ֆիզիկական ստեղնաշարն ակտիվ է"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Պաստառ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Փոխել պաստառը"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ծանուցման ունկնդիր"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Պայմանների մատակարար"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ծանուցումների օգնական"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN-ը ակտիվացված է"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-ն ակտիվացված է <xliff:g id="APP">%s</xliff:g>-ի կողմից"</string>
<string name="vpn_text" msgid="3011306607126450322">"Հպեք` ցանցի կառավարման համար:"</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Ապամրացնել"</string>
<string name="app_info" msgid="6856026610594615344">"Հավելվածի տվյալներ"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 8351f343..8c0da19 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Bantuan Suara"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Konten tersembunyi"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Konten disembunyikan menurut kebijakan"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
@@ -1136,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ubah wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Pemroses Realitas Maya"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Penyedia ketentuan"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asisten notifikasi"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengelola jaringan."</string>
@@ -1564,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Lepas pin"</string>
<string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index f43adcf..b58dc05 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Raddaðstoð"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Læsa núna"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Innihald falið"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Efni falið með reglu"</string>
<string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Snertu til að fá fleiri valkosti."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-villuleit tengd"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Snertu til að slökkva á USB-villuleit."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Tekur við villutilkynningu…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Deila villutilkynningu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deilir villutilkynningu..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Kerfisstjórinn þinn óskaði eftir villutilkynningu til að auðvelda úrræðaleit á þessu tæki. Forritum og gögnum verður hugsanlega deilt."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEILA"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"HAFNA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Skipta um lyklaborð"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Velja lyklaborð"</string>
<string name="show_ime" msgid="2506087537466597099">"Haltu því á skjánum meðan vélbúnaðarlyklaborðið er virkt"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Veggfóður"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Skipta um veggfóður"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Tilkynningahlustun"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Sýndarveruleikavöktun"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Skilyrðaveita"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Tilkynningaaðstoð"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN virkjað"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN er virkjað með <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Snertu til að hafa umsjón með netinu."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Losa"</string>
<string name="app_info" msgid="6856026610594615344">"Forritsupplýsingar"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9e02d34..41ba923 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Blocca ora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Contenuti nascosti in base alle norme"</string>
<string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Tocca per visualizzare più opzioni."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tocca per disattivare il debug USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Recupero della segnalazione di bug…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Condividere la segnalazione di bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Condivisione della segnalazione di bug…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"L\'amministratore IT ha richiesto una segnalazione di bug per poter risolvere più facilmente i problemi di questo dispositivo. Potrebbero essere condivisi dati e app."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"CONDIVIDI"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RIFIUTO"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambia tastiera"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Scegli tastiera"</string>
<string name="show_ime" msgid="2506087537466597099">"Tieni sullo schermo quando è attiva la tastiera fisica"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Sfondo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener di notifica"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Listener realtà virtuale"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provider condizioni"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente notifica"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN attiva"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN attivata da <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tocca per gestire la rete."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Sblocca"</string>
<string name="app_info" msgid="6856026610594615344">"Informazioni app"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 48c4c29..226b390 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -233,7 +233,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"נעל עכשיו"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"התוכן מוסתר"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"התוכן מוסתר על ידי המדיניות"</string>
<string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
@@ -1152,8 +1151,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"טפט"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"מאזין להתראות"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ספק תנאי"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"אסיסטנט ההודעות"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN מופעל"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"גע כדי לנהל את הרשת."</string>
@@ -1602,4 +1604,8 @@
<string name="unpin_target" msgid="3556545602439143442">"בטל הצמדה"</string>
<string name="app_info" msgid="6856026610594615344">"פרטי אפליקציה"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 810d70d..b494851 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -213,8 +213,7 @@
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"対話型レポート"</string>
<string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"ほとんどの場合はこのオプションを使用します。レポートの進行状況を追跡し、問題についての詳細情報を確認することができます。レポート作成に時間がかかってもあまり使用されないセクションは省略されることがあります。"</string>
<string name="bugreport_option_full_title" msgid="6354382025840076439">"完全レポート"</string>
- <!-- no translation found for bugreport_option_full_summary (6687306111256813257) -->
- <skip />
+ <string name="bugreport_option_full_summary" msgid="6687306111256813257">"端末の反応がないとき、または速度が遅すぎるときにシステムへの影響を最小限に抑えたい場合は、このオプションを使用します。またすべてのレポート セクションを表示したい場合にもこのオプションを使用します。スクリーンショットは作成されず、詳細情報も表示できません。"</string>
<plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
<item quantity="other"><xliff:g id="NUMBER_1">%d</xliff:g> 秒後にバグレポートのスクリーンショットが作成されます。</item>
<item quantity="one"><xliff:g id="NUMBER_0">%d</xliff:g> 秒後にバグレポートのスクリーンショットが作成されます。</item>
@@ -230,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"音声アシスト"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"今すぐロック"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g> 件)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"コンテンツが非表示"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ポリシーによって非表示になっているコンテンツ"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
@@ -1053,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"タップしてその他のオプションを表示"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USBデバッグが接続されました"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"タップしてUSBデバッグを無効化"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"バグレポートを取得しています…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"バグレポートを共有しますか?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"バグレポートの共有中…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT 管理者からこの端末のトラブルシューティングに役立てるためバグレポートを共有するようリクエストがありました。アプリやデータが共有されることがあります。"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"共有する"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"共有しない"</string>
<string name="select_input_method" msgid="8547250819326693584">"キーボードの変更"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"キーボードの選択"</string>
<string name="show_ime" msgid="2506087537466597099">"物理キーボードが有効になっている間は、画面に表示されます"</string>
@@ -1141,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"壁紙"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知リスナー"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR リスナー"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"コンディションプロバイダ"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知アシスタント"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPNが有効になりました"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPNが<xliff:g id="APP">%s</xliff:g>により有効化されました"</string>
<string name="vpn_text" msgid="3011306607126450322">"タップしてネットワークを管理します。"</string>
@@ -1551,16 +1547,11 @@
<string name="language_picker_section_suggested" msgid="8414489646861640885">"言語の候補"</string>
<string name="language_picker_section_all" msgid="3097279199511617537">"すべての言語"</string>
<string name="locale_search_menu" msgid="2560710726687249178">"検索"</string>
- <!-- no translation found for work_mode_off_title (8954725060677558855) -->
- <skip />
- <!-- no translation found for work_mode_off_message (3286169091278094476) -->
- <skip />
- <!-- no translation found for work_mode_turn_on (2062544985670564875) -->
- <skip />
- <!-- no translation found for suspended_package_title (3408150347778524435) -->
- <skip />
- <!-- no translation found for suspended_package_message (6341091587106868601) -->
- <skip />
+ <string name="work_mode_off_title" msgid="8954725060677558855">"Work モード OFF"</string>
+ <string name="work_mode_off_message" msgid="3286169091278094476">"仕事用プロファイルで、アプリ、バックグラウンド同期などの関連機能の使用を許可します。"</string>
+ <string name="work_mode_turn_on" msgid="2062544985670564875">"ON にする"</string>
+ <string name="suspended_package_title" msgid="3408150347778524435">"%1$sが無効です"</string>
+ <string name="suspended_package_message" msgid="6341091587106868601">"%1$s管理者によって無効になっています。詳しくは管理者までお問い合わせください。"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"新着メッセージがあります"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"表示するには SMS アプリを開きます"</string>
<string name="user_encrypted_title" msgid="9054897468831672082">"一部機能が制限されている可能性"</string>
@@ -1574,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"固定を解除"</string>
<string name="app_info" msgid="6856026610594615344">"アプリ情報"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 0b164eb..ecef3da 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ხმოვანი ასისტ."</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ახლა ჩაკეტვა"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"შიგთავსი დამალულია"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"შიგთავსი დამალულია წესების შესაბამისად"</string>
<string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"შეეხეთ დამატებითი პარამეტრებისთვის."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB გამართვა შეერთებულია"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"შეეხეთ, რათა შეწყვიტოთ USB-ის გამართვა."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის შექმნა…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"გსურთ ხარვეზის შესახებ ანგარიშის გაზიარება?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"მიმდინარეობს ხარვეზის შესახებ ანგარიშის გაზიარება…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ამ მოწყობილობის პრობლემების აღმოფხვრაში დასახმარებლად, თქვენი IT ადმინისტრატორი ხარვეზის შესახებ ანგარიშს ითხოვს, რა დროსაც შეიძლება გაზიარდეს აპები და მონაცემები."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"გაზიარება"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"უარყოფა"</string>
<string name="select_input_method" msgid="8547250819326693584">"კლავიატურის შეცვლა"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"კლავიატურების არჩევა"</string>
<string name="show_ime" msgid="2506087537466597099">"აქტიური ფიზიკური კლავიატურისას ეკრანზე შენარჩუნება"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ფონი"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ფონის შეცვლა"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"შეტყობინებების მსმენელი"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"მდგომარეობის პროვაიდერი"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"შეტყობინებათა ასისტენტი"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN გააქტიურებულია"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN გააქტიურებულია <xliff:g id="APP">%s</xliff:g>-ის მიერ"</string>
<string name="vpn_text" msgid="3011306607126450322">"შეეხეთ ქსელის სამართავად."</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"ჩამაგრების მოხსნა"</string>
<string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index d803c50..8f5a667 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Дауыс көмекшісі"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Қазір бекіту"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Мазмұн жасырылған"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Мазмұн саясатқа сай жасырылған"</string>
<string name="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
@@ -1136,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Артқы фоны"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Артқы фонын өзгерту"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Хабар бақылағыш"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR тыңдаушы"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Шарт провайдері"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Хабарландыру көмекшісі"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN белсенді"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"ВЖЭ <xliff:g id="APP">%s</xliff:g> арқылы қосылған"</string>
<string name="vpn_text" msgid="3011306607126450322">"Желіні басқару үшін түрту."</string>
@@ -1564,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Босату"</string>
<string name="app_info" msgid="6856026610594615344">"Қолданба ақпараты"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 9f9e961..0c69f930 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ជំនួយសម្លេង"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ចាក់សោឥឡូវនេះ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"បានលាក់មាតិកា"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"មាតិកាត្រូវបានលាក់ដោយផ្អែកលើគោលការណ៍"</string>
<string name="safeMode" msgid="2788228061547930246">"របៀបសុវត្ថិភាព"</string>
@@ -1054,16 +1053,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ប៉ះដើម្បីបានជម្រើសថែមទៀត។"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"បានភ្ជាប់ការកែកំហុសយូអេសប៊ី"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"ប៉ះ ដើម្បីបិទការកែកំហុសយូអេសប៊ី។"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"កំពុងទទួលយករបាយការណ៍កំហុស…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ចែករំលែករបាយការណ៍កំហុសឬ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"កំពុងចែករំលែករបាយកំហុស…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"អ្នកគ្រប់គ្រងផ្នែកព័ត៌មានវិទ្យារបស់អ្នកបានស្នើរបាយការណ៍កំហុសដើម្បីដោះស្រាយកំហុសឧបករណ៍នេះ។ កម្មវិធី និងទិន្នន័យអាចនឹងត្រូវបានចែករំលែក។"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ចែករំលែក"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"បដិសេធ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ប្ដូរក្ដារចុច"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ជ្រើសក្ដារចុច"</string>
<string name="show_ime" msgid="2506087537466597099">"ទុកវានៅលើអេក្រង់ខណៈពេលក្តារចុចពិតប្រាកដកំពុងសកម្ម"</string>
@@ -1142,8 +1137,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ផ្ទាំងរូបភាព"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ប្ដូរផ្ទាំងរូបភាព"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"កម្មវិធីស្ដាប់ការជូនដំណឹង"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ក្រុមហ៊ុនផ្ដល់លក្ខខណ្ឌ"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"ជំនួយការជូនដំណឹង"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"បានធ្វើឲ្យ VPN សកម្ម"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"បានធ្វើឲ្យ VPN សកម្មដោយ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"ប៉ះ ដើម្បីគ្រប់គ្រងបណ្ដាញ។"</string>
@@ -1570,4 +1568,8 @@
<string name="unpin_target" msgid="3556545602439143442">"មិនខ្ទាស់"</string>
<string name="app_info" msgid="6856026610594615344">"ព័ត៌មានកម្មវិធី"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 46ef931..af44c83 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ಈಗ ಲಾಕ್ ಮಾಡಿ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"ವಿಷಯಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ನೀತಿಯಿಂದ ಮರೆಮಾಡಲಾಗಿರುವ ವಿಷಯಗಳು"</string>
<string name="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗೆ ಸ್ಪರ್ಶಿಸಿ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ಡೀಬಗಿಂಗ್ ಸಂಪರ್ಕ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ಡೀಬಗಿಂಗ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ದೋಷದ ವರದಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚುವುದೇ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ಬಗ್ ವರದಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ಈ ಸಾಧನದ ಸಮಸ್ಯೆ ನಿವಾರಿಸಲು ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಬಗ್ ವರದಿಯನ್ನು ವಿನಂತಿಸಿದ್ದಾರೆ. ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ನಿರಾಕರಿಸು"</string>
<string name="select_input_method" msgid="8547250819326693584">"ಕೀಬೋರ್ಡ್ ಬದಲಿಸಿ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ಕೀಬೋರ್ಡ್ಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="show_ime" msgid="2506087537466597099">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಪರದೆಯ ಮೇಲೆ ಇರಿಸಿಕೊಳ್ಳಿ"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ವಾಲ್ಪೇಪರ್"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ವಾಲ್ಪೇಪರ್ ಬದಲಿಸಿ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ಅಧಿಸೂಚನೆ ಕೇಳುಗ"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR ಕೇಳುವಿಕೆ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ಕಂಡೀಶನ್ ಪೂರೈಕೆದಾರರು"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"ಅಧಿಸೂಚನೆ ಸಹಾಯಕ"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ಮೂಲಕ VPN ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
<string name="vpn_text" msgid="3011306607126450322">"ನೆಟ್ವರ್ಕ್ ನಿರ್ವಹಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"ಅನ್ಪಿನ್"</string>
<string name="app_info" msgid="6856026610594615344">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f8d0598..0109279 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"음성 지원"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"지금 잠그기"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>개)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"숨겨진 콘텐츠"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"콘텐츠가 정책에 의해 숨겨졌습니다."</string>
<string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"더 많은 옵션을 확인하려면 터치하세요."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB 디버깅 연결됨"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB 디버깅을 사용하지 않으려면 터치하세요."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"버그 보고서 가져오는 중..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"버그 보고서를 공유하시겠습니까?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"버그 신고서 공유 중..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT 관리자가 이 기기의 문제해결을 위해 버그 보고서를 요청했습니다. 앱과 데이터가 공유될 수 있습니다."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"공유"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"거부"</string>
<string name="select_input_method" msgid="8547250819326693584">"키보드 변경"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"키보드 선택"</string>
<string name="show_ime" msgid="2506087537466597099">"물리적 키보드가 활성 상태인 경우 화면에 켜 둠"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"배경화면"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"알림 수신기"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"조건 제공자"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"알림 어시스턴트"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN이 활성화됨"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN이 <xliff:g id="APP">%s</xliff:g>에 의해 활성화됨"</string>
<string name="vpn_text" msgid="3011306607126450322">"네트워크를 관리하려면 터치하세요."</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"고정 해제"</string>
<string name="app_info" msgid="6856026610594615344">"앱 정보"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 8670af0..09317323 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Үн жардамчысы"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Азыр кулпулоо"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Мазмундар жашырылган"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Тийиштүү саясат боюнча жашырылган мазмундар"</string>
<string name="safeMode" msgid="2788228061547930246">"Коопсуз режим"</string>
@@ -1053,16 +1052,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Көбүрөөк параметр үчүн тийип коюңуз."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB мүчүлүштүктөрдү оңдоо туташтырылган"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB мүчүлүштүктөрдү жоюу мүмкүнчүлүгүн өчүрүү үчүн тийип коюңуз."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Мүчүлүштүк тууралуу кабар алынууда…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Мүчүлүштүк тууралуу баяндама бөлүшүлсүнбү?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Мүчүлүштүк тууралуу баяндама бөлүшүлүүдө…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Бул түзмөктүн бузулууларын аныктап оңдоо үчүн IT администраторуңуз мүчүлүштүктөр тууралуу маалыматты сурап жатат. Колдонмолор менен дайындар бөлүшүлүшү мүмкүн."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"БӨЛҮШҮҮ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ЧЕТКЕ КАГУУ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Баскычтопту өзгөртүү"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Баскычтопторду тандаңыз"</string>
<string name="show_ime" msgid="2506087537466597099">"Баскычтоп иштетилгенде экранда көрүнүп турсун"</string>
@@ -1141,8 +1136,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Тушкагаз"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Тушкагазды өзгөртүү"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Эскертүү тыңшагычы"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Шарт түзүүчү"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Эскертме жардамчысы"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN иштетилди"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> аркылуу жандырылды"</string>
<string name="vpn_text" msgid="3011306607126450322">"желени башкаруу үчүн басыңыз."</string>
@@ -1569,4 +1567,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Кадоодон алып коюу"</string>
<string name="app_info" msgid="6856026610594615344">"Колдонмо тууралуу"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 8f9d820..2d680a9 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ຊ່ວຍເຫຼືອທາງສຽງ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ລັອກດຽວນີ້"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"ເນື້ອຫາຖືກເຊື່ອງໄວ້"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ເນື້ອຫາຖືກເຊື່ອງຕາມນະໂຍບາຍ"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -1136,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ພາບພື້ນຫຼັງ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ປ່ຽນພາບພື້ນຫຼັງ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ໂຕຟັງການແຈ້ງເຕືອນ"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"ຕົວຟັງ VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ຜູ່ສະໜອງເງື່ອນໄຂ"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"ຕົວຊ່ວຍການແຈ້ງເຕືອນ"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"ເປີດນຳໃຊ້ VPN ແລ້ວ"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"ເປີດໃຊ້ VPN ໂດຍ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"ແຕະເພື່ອຈັດການເຄືອຂ່າຍ."</string>
@@ -1564,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"ຖອນປັກໝຸດ"</string>
<string name="app_info" msgid="6856026610594615344">"ຂໍ້ມູນແອັບ"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8e8f5b8..8f29a84 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -233,7 +233,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Užrakinti dabar"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Turinys paslėptas"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Turinys paslėptas vadovaujantis politika"</string>
<string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
@@ -1068,16 +1067,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Palieskite, kad būtų rodoma daugiau parinkčių."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB derinimas prijungtas"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Neleisti USB derinimo."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Pateikiamas pranešimas apie riktą…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bendrinti pranešimą apie riktą?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bendrinamas pranešimas apie riktą..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Jūsų IT administratorius pateikė pranešimo apie riktą užklausą, kad galėtų padėti pašalinti triktis šiame įrenginyje. Programos ir duomenys gali būti bendrinami."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"BENDRINTI"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ATMESTI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviatūros keitimas"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pasirinkti klaviatūras"</string>
<string name="show_ime" msgid="2506087537466597099">"Palikti ekrane, kol fizinė klaviatūra aktyvi"</string>
@@ -1156,8 +1151,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Darbalaukio fonas"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Keisti darbalaukio foną"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pranešimų skaitymo priemonė"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Virtualiosios realybės apdorojimo priemonė"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Sąlygos teikėjas"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pranešimų pagelbiklis"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN suaktyvintas"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN suaktyvino „<xliff:g id="APP">%s</xliff:g>“"</string>
<string name="vpn_text" msgid="3011306607126450322">"Palieskite, kad valdytumėte tinklą."</string>
@@ -1606,4 +1603,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Atsegti"</string>
<string name="app_info" msgid="6856026610594615344">"Programos informacija"</string>
<string name="negative_duration" msgid="5688706061127375131">"–<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5b17105..4456d19 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -231,7 +231,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Balss palīgs"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloķēt tūlīt"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Saturs paslēpts"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Saskaņā ar politiku saturs ir paslēpts."</string>
<string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
@@ -1060,16 +1059,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Citas opcijas"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB atkļūdošana ir pievienota."</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Iespējot USB atkļūdošanu."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Notiek kļūdas pārskata izveide…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vai kopīgot kļūdas pārskatu?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Notiek kļūdas pārskata kopīgošana…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Jūsu IT administrators pieprasīja kļūdas pārskatu, lai palīdzētu novērst problēmu šajā ierīcē. Var tikt kopīgotas lietotnes un dati."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"KOPĪGOT"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"NORAIDĪT"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tastatūras maiņa"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Izvēlēties tastatūru"</string>
<string name="show_ime" msgid="2506087537466597099">"Paturēt ekrānā, kamēr ir aktīva fiziskā tastatūra"</string>
@@ -1148,8 +1143,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fona tapete"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Tapetes maiņa"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Paziņojumu uztvērējs"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Nosacījumu sniedzējs"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Paziņojumu palīgs"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN ir aktivizēts."</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Lietojumprogramma <xliff:g id="APP">%s</xliff:g> aktivizēja VPN."</string>
<string name="vpn_text" msgid="3011306607126450322">"Pieskarieties, lai pārvaldītu tīklu."</string>
@@ -1587,4 +1585,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Atspraust"</string>
<string name="app_info" msgid="6856026610594615344">"Lietotnes informācija"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index d59d1f3..0cb2d48 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помош"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Заклучи сега"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Содржините се скриени"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содржините се скриени поради политиката"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Допри за повеќе опции."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Поврзано е отстранување грешки преку УСБ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Допрете за да се оневозможи отстранувањето грешки преку USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Се зема извештајот за грешки…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Да се сподели извештајот за грешки?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Се споделува извештај за грешки…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Вашиот администратор за информатичка технологија побара извештај за грешки за да ви помогне во отстранувањето на грешките на овој уред. Апликациите и податоците може да бидат споделени."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"СПОДЕЛИ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Измени тастатура"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Избери тастатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Прикажувај го на екранот додека е активна физичката тастатура"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промени тапет"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известувања"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Давател на услов"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помошник за известувања"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"Активирана VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана со <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Допри за да управуваш со мрежата."</string>
@@ -1570,4 +1568,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Откачете"</string>
<string name="app_info" msgid="6856026610594615344">"Информации за апликација"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 61fadea..66a7d85 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"വോയ്സ് സഹായം"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ഇപ്പോൾ ലോക്കുചെയ്യുക"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"കോൺടാക്റ്റുകൾ മറച്ചു"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"നയം അനുസരിച്ച് ഉള്ളടക്കം മറച്ചിരിക്കുന്നു"</string>
<string name="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് സ്പർശിക്കൂ."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ഡീബഗ്ഗിംഗ് കണക്റ്റുചെയ്തു"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ സ്പർശിക്കൂ."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ബഗ് റിപ്പോർട്ട് എടുക്കുന്നു…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ബഗ് റിപ്പോർട്ട് പങ്കിടണോ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ബഗ് റിപ്പോർട്ട് പങ്കിടുന്നു…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ഈ ഉപകരണത്തിലെ പ്രശ്നം പരിഹരിക്കുന്നതിന് നിങ്ങളുടെ ഐടി അഡ്മിൻ ഒരു ബഗ് റിപ്പോർട്ട് അഭ്യർത്ഥിച്ചു. ആപ്സും ഡാറ്റയും പങ്കിടപ്പെട്ടേക്കും."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"പങ്കിടുക"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"നിരസിക്കുക"</string>
<string name="select_input_method" msgid="8547250819326693584">"കീബോഡ് മാറ്റുക"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"കീബോർഡുകൾ തിരഞ്ഞെടുക്കുക"</string>
<string name="show_ime" msgid="2506087537466597099">"ഫിസിക്കൽ കീബോർഡ് സജീവമായിരിക്കുമ്പോൾ സ്ക്രീനിൽ നിലനിർത്തുക"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"വാൾപേപ്പർ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"വാൾപേപ്പർ മാറ്റുക"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"അറിയിപ്പ് ലിസണർ"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR ലിസണർ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"കണ്ടീഷൻ ദാതാവ്"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"അറിയിപ്പ് സഹായി"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN സജീവമാക്കി"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ഉപയോഗിച്ച് VPN പ്രവർത്തനക്ഷമമാക്കി"</string>
<string name="vpn_text" msgid="3011306607126450322">"നെറ്റ്വർക്ക് നിയന്ത്രിക്കാൻ സ്പർശിക്കുക."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"അൺപിൻ ചെയ്യുക"</string>
<string name="app_info" msgid="6856026610594615344">"ആപ്പ് വിവരം"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 1f683cb..566b24d 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Дуут туслах"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Одоо түгжих"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Контентыг нуусан"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Удирдамжийн дагуу нуусан агуулга"</string>
<string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Нэмэлт сонголтыг харахын тулд дарна."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB дебаг холбогдсон"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB дебагийг идэвхгүй болгох бол хүрнэ үү."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Алдааны тайланг авч байна..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Алдааны тайланг хуваалцах уу?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Алдааны тайланг хуваалцаж байна..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Энэ төхөөрөмжийн асуудлыг шийдвэрлэхийн тулд таны IT админ алдааны тайланг хүслээ. Апп болон өгөгдлийг хуваалцсан байж болзошгүй."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ХУВААЛЦАХ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ТАТГАЛЗАХ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Гарыг өөрчлөх"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Гар сонгох"</string>
<string name="show_ime" msgid="2506087537466597099">"Бодит гар идэвхтэй үед үүнийг дэлгэцэнд харуулна уу"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ханын зураг"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ханын зураг солих"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Мэдэгдэл сонсогч"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR сонсогч"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Нөхцөл нийлүүлэгч"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Мэдэгдлийн туслагч"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN идэвхтэй болов"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-г <xliff:g id="APP">%s</xliff:g> идэвхтэй болгов"</string>
<string name="vpn_text" msgid="3011306607126450322">"Сүлжээг удирдах бол хүрнэ үү."</string>
@@ -1566,4 +1563,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
<string name="app_info" msgid="6856026610594615344">"Апп-н мэдээлэл"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 91b27ec..3b38988 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"व्हॉइस सहाय्य"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"आता लॉक करा"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"लपविलेली सामग्री"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"धोरणाद्वारे सामग्री लपविली"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"अधिक पर्यायांसाठी स्पर्श करा."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग करणे कनेक्ट केले"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करणे अक्षम करण्यासाठी स्पर्श करा."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"दोष अहवाल घेत आहे..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग अहवाल सामायिक करायचा?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"दोष अहवाल सामायिक करीत आहे..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"आपल्या IT प्रशासकाने या डिव्हाइसच्या समस्येचे निवारण करण्यात मदत करण्यासाठी दोष अहवालाची विनंती केली. अॅप्स आणि डेटा सामायिक केले जाऊ शकतात."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"सामायिक करा"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"नकार द्या"</string>
<string name="select_input_method" msgid="8547250819326693584">"कीबोर्ड बदला"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"कीबोर्ड निवडा"</string>
<string name="show_ime" msgid="2506087537466597099">"भौतिक कीबोर्ड सक्रिय असताना त्यास स्क्रीनवर ठेवा"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदला"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना ऐकणारा"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR श्रोता"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"अट प्रदाता"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"सूचना सहाय्यक"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> द्वारे VPN सक्रिय केले आहे"</string>
<string name="vpn_text" msgid="3011306607126450322">"नेटवर्क व्यवस्थापित करण्यासाठी स्पर्श करा."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"अनपिन करा"</string>
<string name="app_info" msgid="6856026610594615344">"अॅप माहिती"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 5555663..9900157 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Bantuan Suara"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Kandungan tersembunyi"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Kandungan disembunyikan oleh dasar"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Sentuh untuk mendapatkan lagi pilihan."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Penyahpepijatan USB disambungkan"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk melumpuhkan penyahpepijatan USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Mengambil laporan pepijat…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Kongsi laporan pepijat?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Berkongsi laporan pepijat…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Pentadbir IT anda meminta laporan pepijat untuk membantu menyelesaikan masalah peranti ini. Apl dan data mungkin dikongsi."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"KONGSI"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TOLAK"</string>
<string name="select_input_method" msgid="8547250819326693584">"Tukar papan kekunci"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pilih papan kekunci"</string>
<string name="show_ime" msgid="2506087537466597099">"Pastikannya pada skrin, semasa papan kekunci fizikal aktif"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Kertas dinding"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Tukar kertas dinding"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Pembekal keadaan"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pembantu pemberitahuan"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengurus rangkaian."</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Nyahsemat"</string>
<string name="app_info" msgid="6856026610594615344">"Maklumat apl"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index c9f2ffc..265a47f 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"အသံ အကူအညီ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ယခု သော့ပိတ်ရန်"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"၉၉၉+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"အကြောင်းအရာများ ဝှက်ထား"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"မူဝါဒမှ အကြောင်းအရာများကို ဝှက်ထားသည်"</string>
<string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ထပ်မံရွေးချယ်စရာများအတွက် ထိပါ"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB အမှားစစ်ခြင်းအား ချိတ်ဆက်ထားသည်"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ဒီဘာဂင် ပိတ်ရန် ထိပါ။"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ချွတ်ယွင်းချက် အစီရင်ခံစာပြုစုနေသည်..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို မျှဝေမလား။"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ချွတ်ယွင်းမှုအစီရင်ခံစာ မျှဝေနေသည်…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ဤစက်ပစ္စည်းကို ပြဿနာအဖြေရှာရာတွင် ကူညီရန် သင့်အိုင်တီစီမံခန့်ခွဲသူသည် ချွတ်ယွင်းချက်အစီရင်ခံစာကို တောင်းဆိုထားသည်။ အက်ပ်များနှင့် ဒေတာကိုမျှဝေထားနိုင်ပါသည်။"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"မျှဝေပါ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ငြင်းပယ်ပါ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ကီးဘုတ် ပြောင်းလဲရန်"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ကီးဘုတ်များကို ရွေးရန်"</string>
<string name="show_ime" msgid="2506087537466597099">"စက်၏ကီးဘုတ်ကိုအသုံးပြုနေစဉ် ၎င်းကိုမျက်နှာပြင်ပေါ်တွင် ထားပါ"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"နောက်ခံ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"နောက်ခံပြောင်းခြင်း"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"အကြောင်းကြားချက် နားတောင်သူ"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR နားထောင်မှုစနစ်"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"အခြေအနေ စီမံပေးသူ"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"သတိပေးချက် အကူ"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN ဖွင့်ထားပါသည်"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g>မှVPNအလုပ်လုပ်နေသည်"</string>
<string name="vpn_text" msgid="3011306607126450322">"ကွန်ရက် ထိန်းသိမ်းရန် တို့ထိပါ"</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"ဖြုတ်ပါ"</string>
<string name="app_info" msgid="6856026610594615344">"အက်ပ်အချက်အလက်"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 4ff6608..b0b21ee 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Talehjelp"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nå"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Innholdet er skjult"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innholdet er skjult i henhold til retningslinjene"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Trykk for å se flere alternativer."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-feilsøking tilkoblet"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Trykk for å slå av USB-feilsøking."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kjører feilrapport …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vil du dele feilrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deler feilrapporten …"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT-administratoren har bedt om en feilrapport for å hjelpe med feilsøkingen på denne enheten. Apper og data kan bli delt."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DEL"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AVSLÅ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Endre tastatur"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Velg tastatur"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha den på skjermen mens det fysiske tastaturet er aktivt"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrunnsbilde"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Velg bakgrunnsbilde"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Varsellytteren"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Lyttetjeneste for virtuell virkelighet"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Betingelsesleverandør"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Varselassistent"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN er aktivert"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN er aktivert av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Trykk for å administrere nettverket."</string>
@@ -1570,4 +1567,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Løsne"</string>
<string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 80f1602..1059a7f 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"आवाज सहायता"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"अब बन्द गर्नुहोस्"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"९९९+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"लुकेका सामाग्रीहरू"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"नीतिद्वारा लुकाइएका सामग्री"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -1142,8 +1141,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"वालपेपर"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"वालपेपर परिवर्तन गर्नुहोस्"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना सुन्नेवाला"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR श्रोता"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"सर्त प्रदायक"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"सूचना सहायक"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय भयो"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g>द्वारा सक्रिय गरिएको हो"</string>
<string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबन्ध गर्न छुनुहोस्।"</string>
@@ -1570,4 +1571,8 @@
<string name="unpin_target" msgid="3556545602439143442">"अनपिन गर्नुहोस्"</string>
<string name="app_info" msgid="6856026610594615344">"अनुप्रयोगका बारे जानकारी"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 06b63b9..8e030dd 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Content verborgen op basis van beleid"</string>
<string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Tik voor meer opties."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tik om USB-foutopsporing uit te schakelen."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Bugrapport genereren…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Bugrapport delen?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Bugrapport delen…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Je IT-beheerder heeft een bugrapport aangevraagd om problemen met dit apparaat op te lossen. Apps en gegevens kunnen worden gedeeld."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELEN"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"WEIGEREN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Toetsenbord wijzigen"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Toetsenborden kiezen"</string>
<string name="show_ime" msgid="2506087537466597099">"Dit op het scherm weergeven terwijl het fysieke toetsenbord actief is"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Achtergrond"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Achtergrond wijzigen"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener voor meldingen"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR-listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provider van voorwaarden"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Meldingsassistent"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN is geactiveerd"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN wordt geactiveerd door <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Raak aan om het netwerk te beheren."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Losmaken"</string>
<string name="app_info" msgid="6856026610594615344">"App-info"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 89d2df8..93e8181 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ਵੌਇਸ ਅਸਿਸਟ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ਹੁਣ ਲੌਕ ਕਰੋ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"ਸਮੱਗਰੀਆਂ ਲੁਕਾਈਆਂ ਗਈਆਂ"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ਨੀਤੀ ਦੁਆਰਾ ਸਮੱਗਰੀ ਲੁਕਾਈ ਗਈ"</string>
<string name="safeMode" msgid="2788228061547930246">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਸਪਰਸ਼ ਕਰੋ।"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ਡੀਬਗਿੰਗ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਉਣ ਲਈ ਛੋਹਵੋ।"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"ਬੱਗ ਰਿਪਰੋਟ ਪ੍ਰਾਪਤ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"ਕੀ ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕਰਨੀ ਹੈ?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"ਬੱਗ ਰਿਪੋਰਟ ਸਾਂਝੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ਤੁਹਾਡੇ IT ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਇਸ ਡੀਵਾਈਸ ਦੀ ਸਮੱਸਿਆ ਨੂੰ ਠੀਕ ਕਰਨ ਵਿੱੱਚ ਮਦਦ ਲਈ ਬੱਗ ਰਿਪੋਰਟ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ। ਐਪਾਂ ਅਤੇ ਡੈਟੇ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ਸਾਂਝੀ ਕਰੋ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
<string name="select_input_method" msgid="8547250819326693584">"ਕੀਬੋਰਡ ਬਦਲੋ"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"ਕੀਬੋਰਡਸ ਚੁਣੋ"</string>
<string name="show_ime" msgid="2506087537466597099">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਸਰਗਰਮ ਹੋਣ ਦੌਰਾਨ ਇਸ ਨੂੰ ਸਕ੍ਰੀਨ \'ਤੇ ਬਣਾਈ ਰੱਖੋ"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"ਵਾਲਪੇਪਰ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"ਵਾਲਪੇਪਰ ਬਦਲੋ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ਸੂਚਨਾ ਸੁਣਨ ਵਾਲਾ"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR ਸਰੋਤਾ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ਸਥਿਤੀ ਪ੍ਰਦਾਤਾ"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"ਸੂਚਨਾ ਸਹਾਇਕ"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN ਸਕਿਰਿਆ ਕੀਤਾ"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> ਰਾਹੀਂ ਸਕਿਰਿਆ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="vpn_text" msgid="3011306607126450322">"ਨੈਟਵਰਕ ਵਿਵਸਥਿਤ ਕਰਨ ਲਈ ਛੋਹਵੋ।"</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"ਅਨਪਿੰਨ ਕਰੋ"</string>
<string name="app_info" msgid="6856026610594615344">"ਐਪ ਜਾਣਕਾਰੀ"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 773cc88..ae801ae 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -233,7 +233,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asystent głosowy"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zablokuj teraz"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Treści ukryte"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Treść ukryta z powodu zasad"</string>
<string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
@@ -1068,16 +1067,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Kliknij, by zobaczyć więcej opcji."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotknij, aby wyłączyć debugowanie USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Zgłaszam błąd…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Udostępnić raport o błędzie?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Udostępniam raport o błędzie…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administrator poprosił o raport o błędzie, który pomoże w rozwiązaniu problemów na tym urządzeniu. Mogą zostać udostępnione aplikacje i dane."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"UDOSTĘPNIJ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODRZUĆ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Zmień klawiaturę"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Wybierz klawiatury"</string>
<string name="show_ime" msgid="2506087537466597099">"Pozostaw na ekranie, gdy aktywna jest klawiatura fizyczna"</string>
@@ -1156,8 +1151,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Zmień tapetę"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Odbiornik powiadomień"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Odbiornik rzeczywistości wirtualnej"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Dostawca warunków"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asystent powiadomień"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN aktywny"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Obsługa sieci VPN została włączona przez aplikację <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotknij, aby zarządzać siecią."</string>
@@ -1606,4 +1603,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Odepnij"</string>
<string name="app_info" msgid="6856026610594615344">"O aplikacji"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 2e55c37..ce7d77f 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ajuda de voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração do USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Plano de fundo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar plano de fundo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ouvinte de notificações"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Ouvinte de RV"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condições"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente de notificação"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string>
<string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 548ef45..a25cbfe 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Assist. de voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desat. a depuração USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"A criar relatório de erro…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Pretende partilhar o relatório de erro?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"A partilhar relatório de erro…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"O seu administrador de TI solicitou um relatório de erro para ajudar na resolução de problemas deste dispositivo. As aplicações e os dados podem ser partilhados."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PARTILHAR"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter no ecrã enquanto o teclado físico estiver ativo"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagem de fundo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar imagem de fundo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviço de escuta de notificações"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Serviço de escuta de RV"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fornecedor de condição"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente de notificações"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN foi ativada pelo <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerir a rede."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Soltar"</string>
<string name="app_info" msgid="6856026610594615344">"Informações da aplicação"</string>
<string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 2e55c37..ce7d77f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ajuda de voz"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conteúdo ocultado pela política"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Toque para ver mais opções."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração do USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Gerando relatório do bug..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Compartilhar relatório do bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Compartilhando relatório do bug…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Seu administrador de TI solicitou um relatório de bug para ajudar a resolver problemas deste dispositivo. É possível que apps e dados sejam compartilhados."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTILHAR"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECUSAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Alterar teclado"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Escolher teclados"</string>
<string name="show_ime" msgid="2506087537466597099">"Manter na tela enquanto o teclado físico estiver ativo"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Plano de fundo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar plano de fundo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ouvinte de notificações"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Ouvinte de RV"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condições"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente de notificação"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string>
<string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 57be99c0..16b0312 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -231,7 +231,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Asistent vocal"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Blocați acum"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Conținutul este ascuns"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Conținutul este ascuns conform politicii"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
@@ -1060,16 +1059,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Atingeți pentru mai multe opțiuni."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depanarea USB este conectată"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Atingeți pentru a dezactiva depanarea USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Se creează un raport de eroare…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Trimiteți raportul de eroare?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Se trimite raportul de eroare…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administratorul IT a solicitat un raport de eroare pentru a remedia problemele acestui dispozitiv. Este posibil să se permită accesul la date și aplicații."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"TRIMITEȚI"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUZAȚI"</string>
<string name="select_input_method" msgid="8547250819326693584">"Schimbați tastatura"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Alegeți tastaturi"</string>
<string name="show_ime" msgid="2506087537466597099">"Se păstrează pe ecran cât timp este activată tastatura fizică"</string>
@@ -1148,8 +1143,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagine de fundal"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Modificați imaginea de fundal"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviciu de citire a notificărilor"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Instrument de ascultare pentru Realitatea virtuală"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Furnizor de condiții"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent pentru notificări"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN activat"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Atingeți pentru a gestiona rețeaua."</string>
@@ -1587,4 +1584,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Anulați fixarea"</string>
<string name="app_info" msgid="6856026610594615344">"Informații despre aplicație"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 291f53e..971dbfb 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -233,7 +233,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Аудиоподсказки"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Заблокировать"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Содержимое скрыто"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Содержимое скрыто в соответствии с заданными правилами"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
@@ -1152,8 +1151,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновый рисунок"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба просмотра уведомлений"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Поставщик условий"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ассистент уведомлений"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"Сеть VPN активна"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Сеть VPN активирована приложением <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Нажмите, чтобы открыть настройки."</string>
@@ -1602,4 +1604,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Открепить"</string>
<string name="app_info" msgid="6856026610594615344">"О приложении"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index a44933f..ca638fa0 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"හඬ සහායක"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"දැන් අගුළු දමන්න"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"සැඟවුණු සම්බන්ධතා"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"ප්රතිපත්තිය විසින් අන්තර්ගතය සඟවන ලදී"</string>
<string name="safeMode" msgid="2788228061547930246">"ආරක්ෂිත ආකාරය"</string>
@@ -1138,8 +1137,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"බිතුපත"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"බිතුපත වෙනස් කරන්න"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"දැනුම්දීම් අසන්නා"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR සවන් දෙන්නා"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"තත්ත්වය සපයන්නා"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"දැනුම්දීම් සහායක"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN ක්රියාත්මකයි"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> මඟින් VPN සක්රීය කරන ලදි"</string>
<string name="vpn_text" msgid="3011306607126450322">"ජාලය කළමනාකරණය කිරීමට ස්පර්ශ කරන්න."</string>
@@ -1566,4 +1567,8 @@
<string name="unpin_target" msgid="3556545602439143442">"ගලවන්න"</string>
<string name="app_info" msgid="6856026610594615344">"යෙදුම් තොරතුරු"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 80a4293..e33a623 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -233,7 +233,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Hlasový asistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Uzamknúť"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Obsah je na základe pravidiel skrytý"</string>
<string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
@@ -1068,16 +1067,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Ďalšie možnosti zobrazíte klepnutím."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ladenie cez USB pripojené"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Klepnutím zakážete ladenie cez USB"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Preberá sa hlásenie chyby…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Chcete zdieľať hlásenie chyby?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Zdieľa sa hlásenie chyby…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Správca IT si vyžiadal hlásenie chyby, aby mohol vyriešiť problém na tomto zariadení. Aplikácie a dáta môžu byť zdieľané."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ZDIEĽAŤ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ODMIETNUŤ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Zmeniť klávesnicu"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Vybrať klávesnicu"</string>
<string name="show_ime" msgid="2506087537466597099">"Ponechať na obrazovke, keď je aktívna fyzická klávesnica"</string>
@@ -1156,8 +1151,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Zmeniť tapetu"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikácia na počúvanie upozornení"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Prijímač VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovateľ podmienky"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent upozornení"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"Sieť VPN je aktivovaná"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikáciu <xliff:g id="APP">%s</xliff:g> aktivovala sieť VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotykom môžete spravovať sieť."</string>
@@ -1606,4 +1603,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Uvoľniť"</string>
<string name="app_info" msgid="6856026610594615344">"Info o aplikácii"</string>
<string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5e85770..9661b82 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -233,7 +233,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Glas. pomočnik"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Zakleni zdaj"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Vsebina je skrita"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Pravilnik je skril vsebino"</string>
<string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
@@ -1068,16 +1067,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Za več možnosti se dotaknite."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Iskanje in odpravljanje napak USB je povezano"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotaknite se, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Zajemanje poročila o napakah …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite poslati poročilo o napakah?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Pošiljanje poročila o napakah …"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Skrbnik za IT je zahteval poročilo o napakah za pomoč pri odpravljanju napak v tej napravi. Aplikacije in podatki bodo morda dani v skupno rabo."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SKUPNA RABA"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"NE SPREJMEM"</string>
<string name="select_input_method" msgid="8547250819326693584">"Sprememba tipkovnice"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Izbira tipkovnic"</string>
<string name="show_ime" msgid="2506087537466597099">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
@@ -1156,8 +1151,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ozadje"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Spreminjanje ozadja"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Poslušalec obvestil"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Poslušalec za navidezno resničnost"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ponudnik pogojev"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomočnik za obvestila"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktivirala aplikacija <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
@@ -1606,4 +1603,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Odpenjanje"</string>
<string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 9c9268b..a8f44d1 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ndihma zanore"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Kyç tani"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Përmbajtjet janë të fshehura"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Përmbajtja është e fshehur për shkak të politikës"</string>
<string name="safeMode" msgid="2788228061547930246">"Modaliteti i sigurisë"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Prek për më shumë opsione."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Korrigjuesi i USB-së i lidhur"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Prek për të çaktivizuar korrigjimin e gabimeve të USB-së."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Po merret raporti i defekteve në kod…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Të ndahet raporti i defektit në kod?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Po ndan raportin e defekteve në kod..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administratori i teknologjisë së informacionit kërkoi një raport të defekteve në kod për të ndihmuar me zgjidhjen e problemeve. Aplikacioni dhe të dhënat mund të ndahen."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"SHPËRNDA"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REFUZO"</string>
<string name="select_input_method" msgid="8547250819326693584">"Ndërro tastierë"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Zgjidh tastierat"</string>
<string name="show_ime" msgid="2506087537466597099">"Mbaje në ekran ndërsa tastiera fizike është aktive"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Imazhi i sfondit"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ndrysho imazhin e sfondit"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Dëgjues njoftimesh"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ofrues kushtesh"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistenti i njoftimeve"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN-ja u aktivizua"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-ja është aktivizuar nga <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Prek për të menaxhuar rrjetin."</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Zhgozhdo"</string>
<string name="app_info" msgid="6856026610594615344">"Informacioni mbi aplikacionin"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 528832f..f771dec 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -231,7 +231,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Гласовна помоћ"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Закључај одмах"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Садржај је сакривен"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Садржај је сакривен смерницама"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
@@ -1060,16 +1059,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Додирните за још опција."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Отклањање грешака са USB-а је успостављено"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Додирните да бисте онемогућили отклањање грешака са USB-а."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Извештај о грешци се генерише…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Желите ли да поделите извештај о грешци?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Дели се извештај о грешци…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ИТ администратор је затражио извештај о грешци ради лакшег решавања проблема у вези са овим уређајем. Апликације и подаци могу да се деле."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ДЕЛИ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ОДБИЈ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Промените тастатуру"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Изаберите тастатуре"</string>
<string name="show_ime" msgid="2506087537466597099">"Задржи га на екрану док је физичка тастатура активна"</string>
@@ -1148,8 +1143,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Позадина"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Монитор обавештења"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Обрађивач за виртуелну реалност"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Добављач услова"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помоћник за обавештења"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN је активиран"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Апликација <xliff:g id="APP">%s</xliff:g> је активирала VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Додирните да бисте управљали мрежом."</string>
@@ -1587,4 +1584,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Откачи"</string>
<string name="app_info" msgid="6856026610594615344">"Информације о апликацији"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index daa767a..5a86879 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Innehåll har dolts"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Innehåll har dolts p.g.a. en policy"</string>
<string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Visa fler alternativ genom att trycka."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tryck om du vill inaktivera USB-felsökning."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Felrapporten överförs …"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Vill du dela felrapporten?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Felrapporten delas …"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"IT-administratören har bett om en felrapport som hjälp vid felsökningen av den här enheten. Appar och data kan komma att delas."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"DELA"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"AVVISA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Byt tangentbord"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Välj tangentbord"</string>
<string name="show_ime" msgid="2506087537466597099">"Ha kvar den på skärmen när det fysiska tangentbordet används"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ändra bakgrund"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Meddelandelyssnare"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Lyssnare för virtuell verklighet"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Leverantör"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Aviseringsassistent"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN är aktiverat"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveras av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tryck om du vill hantera nätverket."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Lossa"</string>
<string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
<string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d807aac..aeac0ad 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -231,7 +231,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Usaidizi wa Sauti"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Funga sasa"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Maudhui yamefichwa"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Maudhui yamefichwa kulingana na sera"</string>
<string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
@@ -1138,8 +1137,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Mandhari"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha mandhari"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Kisikilizi cha arifa"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Kisikilizaji cha Uhalisia Pepe"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Mtoa masharti"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Mratibu wa arifa"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN imewezeshwa"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN imeamilishwa na <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Gusa ili kudhibiti mtandao."</string>
@@ -1566,4 +1567,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Bandua"</string>
<string name="app_info" msgid="6856026610594615344">"Maelezo ya programu"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 40011d2..baa2c7b 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"குரல் உதவி"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"இப்போது பூட்டு"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"மறைந்துள்ள உள்ளடக்கம்"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"கொள்கையின்படி உள்ளடக்கம் மறைக்கப்பட்டது"</string>
<string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"கூடுதல் விருப்பங்களுக்காகத் தொடவும்."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB பிழைத்திருத்தத்தை முடக்க, தொடவும்."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"பிழை அறிக்கையை எடுக்கிறது…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"பிழை அறிக்கையைப் பகிரவா?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"பிழை அறிக்கையைப் பகிர்கிறது…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"இந்தச் சாதனத்தின் பிழைகாண்பதற்கு உதவ, உங்கள் ஐடி நிர்வாகி பிழை அறிக்கையைக் கோரியுள்ளார். பயன்பாடுகளும் தரவும் பகிரப்படலாம்."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"பகிர்"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"வேண்டாம்"</string>
<string name="select_input_method" msgid="8547250819326693584">"விசைப்பலகையை மாற்று"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"விசைப்பலகைகளைத் தேர்வுசெய்க"</string>
<string name="show_ime" msgid="2506087537466597099">"கைமுறை விசைப்பலகை இயக்கத்தில் இருக்கும் போது IMEஐ திரையில் வைத்திரு"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"வால்பேப்பர்"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"வால்பேப்பரை மாற்று"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"அறிவிப்புகளைக் கண்காணிக்கும் சேவை"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"நிபந்தனை வழங்குநர்"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"அறிவிப்பு உதவி"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN செயல்படுத்தப்பட்டது"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ஆல் VPN செயல்படுத்தப்பட்டது"</string>
<string name="vpn_text" msgid="3011306607126450322">"நெட்வொர்க்கை நிர்வகிக்கத் தொடவும்."</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"பின்னை அகற்று"</string>
<string name="app_info" msgid="6856026610594615344">"பயன்பாட்டுத் தகவல்"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 22aa04d..d8c1e05 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"వాయిస్ సహాయకం"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ఇప్పుడు లాక్ చేయండి"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"కంటెంట్లు దాచబడ్డాయి"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"విధానం ద్వారా కంటెంట్లు దాచబడ్డాయి"</string>
<string name="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"మరిన్ని ఎంపికల కోసం తాకండి."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB డీబగ్గింగ్ కనెక్ట్ చేయబడింది"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB డీబగ్గింగ్ను నిలిపివేయడానికి తాకండి."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"బగ్ నివేదికను తీస్తోంది…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"బగ్ నివేదికను భాగస్వామ్యం చేయాలా?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"బగ్ నివేదికను భాగస్వామ్యం చేస్తోంది..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"మీ ఐటి నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. అనువర్తనాలు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"భాగస్వామ్యం చేయి"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"తిరస్కరిస్తున్నాను"</string>
<string name="select_input_method" msgid="8547250819326693584">"కీబోర్డ్ను మార్చు"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"కీబోర్డ్లను ఎంచుకోండి"</string>
<string name="show_ime" msgid="2506087537466597099">"దీన్ని భౌతిక కీబోర్డ్ సక్రియంగా ఉన్నప్పుడు స్క్రీన్పై ఉంచుతుంది"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"వాల్పేపర్"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"వాల్పేపర్ను మార్చండి"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"నోటిఫికేషన్ పరిశీలన"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR పరిశీలన"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"షరతు ప్రదాత"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"నోటిఫికేషన్ సహాయకం"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN సక్రియం చేయబడింది"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ద్వారా VPN సక్రియం చేయబడింది"</string>
<string name="vpn_text" msgid="3011306607126450322">"నెట్వర్క్ను నిర్వహించడానికి తాకండి."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"అన్పిన్ చేయి"</string>
<string name="app_info" msgid="6856026610594615344">"అనువర్తన సమాచారం"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2e6f62e..0b0805c 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"ตัวช่วยเสียง"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ล็อกเลย"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"เนื้อหาถูกซ่อนไว้"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"มีการซ่อนเนื้อหาโดยนโยบาย"</string>
<string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"แตะเพื่อดูตัวเลือกเพิ่มเติม"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"แตะเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"กำลังสร้างรายงานข้อบกพร่อง…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"แชร์รายงานข้อบกพร่องไหม"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"กำลังแชร์รายงานข้อบกพร่อง…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"ผู้ดูแลระบบไอทีของคุณขอรายงานข้อบกพร่องเพื่อช่วยในการแก้ปัญหาอุปกรณ์นี้ อาจมีการแชร์แอปและข้อมูล"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"แชร์"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ปฏิเสธ"</string>
<string name="select_input_method" msgid="8547250819326693584">"เปลี่ยนแป้นพิมพ์"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"เลือกแป้นพิมพ์"</string>
<string name="show_ime" msgid="2506087537466597099">"เปิดทิ้งไว้บนหน้าจอในระหว่างใช้งานแป้นพิมพ์จริง"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"วอลเปเปอร์"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ตัวฟังการแจ้งเตือน"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Listener ความเป็นจริงเสมือน"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ผู้เสนอเงื่อนไข"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"ผู้ช่วยการแจ้งเตือน"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN เปิดใช้งานแล้ว"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"เปิดใช้งาน VPN โดย <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"แตะเพื่อจัดการเครือข่าย"</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"เลิกปักหมุด"</string>
<string name="app_info" msgid="6856026610594615344">"ข้อมูลแอป"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 71c3460..ed669c4 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"I-lock ngayon"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Nakatago ang mga content"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Itinago ang mga content alinsunod sa patakaran"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Pindutin para sa higit pang mga opsyon."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Pindutin upang i-disable ang pagde-debug ng USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Kinukuha ang ulat ng bug…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Gusto mo bang ibahagi ang ulat ng bug?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Ibinabahagi ang ulat ng bug…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Humiling ang iyong IT admin ng isang ulat ng bug upang makatulong sa pag-troubleshoot sa device na ito. Maaaring ibahagi ang mga app at data."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"IBAHAGI"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"TANGGIHAN"</string>
<string name="select_input_method" msgid="8547250819326693584">"Baguhin ang keyboard"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Pumili ng mga keyboard"</string>
<string name="show_ime" msgid="2506087537466597099">"Panatilihin ito sa screen habang aktibo ang pisikal na keyboard"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Baguhin ang wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"VR listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Nagbibigay ng kundisyon"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"Naka-activate ang VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Isinaaktibo ang VPN ng <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Pindutin upang pamahalaan ang network."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"I-unpin"</string>
<string name="app_info" msgid="6856026610594615344">"Impormasyon ng app"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index c60983b..588ed7a 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Sesli Yardım"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Şimdi kilitle"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"İçerik gizlendi"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"İçerikler politika nedeniyle gizlendi"</string>
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Daha fazla seçenek için dokunun."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB hata ayıklaması bağlandı"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Hata raporu alınıyor…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Hata raporu paylaşılsın mı?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Hata raporu paylaşılıyor..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"BT yöneticiniz, bu cihazda sorun gidermeye yardımcı olması için bir hata raporu istedi. Uygulamalar ve veriler paylaşılabilir."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"PAYLAŞ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REDDET"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klavyeyi değiştir"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Klavyeyi seç"</string>
<string name="show_ime" msgid="2506087537466597099">"Fiziksel klavye etkin durumdayken ekranda tut"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Duvar Kağıdı"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Duvar kağıdını değiştir"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirim dinleyici"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Sanal Gerçeklik dinleyici"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Durum sağlayıcı"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Bildirim yardımcısı"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN etkinleştirildi"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN, <xliff:g id="APP">%s</xliff:g> tarafından etkinleştirildi"</string>
<string name="vpn_text" msgid="3011306607126450322">"Ağı yönetmek için dokunun."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Sabitlemeyi kaldır"</string>
<string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index ed0a978..5ed4018 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -233,7 +233,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Голос. підказки"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Блокувати зараз"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Вміст сховано"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Вміст сховано згідно з правилом"</string>
<string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
@@ -1068,16 +1067,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Торкніться, щоб побачити більше опцій."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Налагодження USB завершено"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Торкніться, щоб вимкнути налагодження USB."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Створюється повідомлення про помилку…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Надіслати звіт про помилку?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Надсилається звіт про помилку…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Ваш IT-адміністратор просить надіслати повідомлення про помилку, щоб вирішити проблему з пристроєм. Він може отримати доступ до ваших додатків і даних."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ПОДІЛИТИСЯ"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"ВІДХИЛИТИ"</string>
<string name="select_input_method" msgid="8547250819326693584">"Змінити клавіатуру"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Вибрати клавіатури"</string>
<string name="show_ime" msgid="2506087537466597099">"Утримуйте на екрані, коли активна фізична клавіатура"</string>
@@ -1156,8 +1151,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновий мал."</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба читання сповіщень"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Обробник віртуальної реальності"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Постачальник умов"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Диспетчер сповіщень"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"Мережу VPN активовано"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Мережу VPN активовано програмою <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Торкніться, щоб керувати мережею."</string>
@@ -1606,4 +1603,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Відкріпити"</string>
<string name="app_info" msgid="6856026610594615344">"Про додаток"</string>
<string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index d314025..faa01b7 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Voice Assist"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"ابھی مقفل کریں"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"مواد مخفی ہیں"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"مواد پالیسی کے تحت مخفی ہے"</string>
<string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"مزید اختیارات کیلئے ٹچ کریں۔"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB ڈیبگ کرنا مربوط ہو گیا"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ڈیبگنگ کو غیر فعال کرنے کیلئے ٹچ کریں۔"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"بگ رپورٹ لی جا رہی ہے…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"بگ رپورٹ کا اشتراک کریں؟"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"بگ رپورٹ کا اشتراک ہو رہا ہے…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"آپ کے IT منتظم نے اس آلہ کا مسئلہ حل کرنے میں مدد کیلئے ایک بگ رپورٹ کی درخواست کی ہے۔ ایپس اور ڈیٹا کا اشتراک ہو سکتا ہے۔"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"اشتراک کریں"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"مسترد کریں"</string>
<string name="select_input_method" msgid="8547250819326693584">"کی بورڈ تبدیل کریں"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"کی بورڈز منتخب کریں"</string>
<string name="show_ime" msgid="2506087537466597099">"جب فزیکل کی بورڈ فعال ہو تو IME کو اسکرین پر رکھیں"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"وال پیپر"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"وال پیپر تبدیل کریں"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"اطلاع سننے والا"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"شرط فراہم کنندہ"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"اطلاع کا معاون"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN فعال ہوگیا"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> کے ذریعہ VPN فعال ہے"</string>
<string name="vpn_text" msgid="3011306607126450322">"نیٹ ورک کا نظم کرنے کیلئے چھوئیں۔"</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"پن ہٹائیں"</string>
<string name="app_info" msgid="6856026610594615344">"ایپ کی معلومات"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 8da4e41..205c17b 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ovozli yordam"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Qulflash"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Kontent yashirildi"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Qoidaga muvofiq kontent yashirilgan"</string>
<string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Sozlash uchun bosing."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"O‘chirib qo‘yish uchun bosing."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Xatoliklar hisoboti olinmoqda…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Xatoliklar hisoboti yuborilsinmi?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Xatoliklar hisoboti yuborilmoqda…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Administratoringiz bu qurilma nosozliklarini tuzatish uchun xatoliklar hisobotini so‘ramoqda. Ilova va ma’lumotlardan foydalanilishi mumkin."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"ULASHISH"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RAD ETISH"</string>
<string name="select_input_method" msgid="8547250819326693584">"Klaviaturani o‘zgartirish"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Klaviaturani tanlash"</string>
<string name="show_ime" msgid="2506087537466597099">"Tashqi klaviaturadan foydalanilayotganda buni ekranda saqlab turish"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fon rasmi"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Fon rasmini o‘zgartirish"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirishnoma tinglovchisi"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Shartlarni taqdim etuvchi"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Bildirishnoma yordamchisi"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN faollashtirildi"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> tomonidan faollashtirilgan"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tarmoqni boshqarish uchun bosing."</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Olib tashlash"</string>
<string name="app_info" msgid="6856026610594615344">"Ilova haqida"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 3dcab7d..0de9fae 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Trợ lý thoại"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Khóa ngay"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Nội dung bị ẩn"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Nội dung bị ẩn theo chính sách"</string>
<string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
@@ -1136,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Hình nền"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Thay đổi hình nền"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Trình xử lý thông báo"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Trình nghe VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Trình cung cấp điều kiện"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Trợ lý thông báo"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"Đã kích hoạt VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN được <xliff:g id="APP">%s</xliff:g> kích hoạt"</string>
<string name="vpn_text" msgid="3011306607126450322">"Chạm để quản lý mạng."</string>
@@ -1564,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Bỏ ghim"</string>
<string name="app_info" msgid="6856026610594615344">"Thông tin ứng dụng"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 58d385d..448a03e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"语音助理"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g> 条)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"内容已隐藏"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"内容已隐藏(根据政策规定)"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"触摸以查看更多选项。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已连接到USB调试"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"触摸可停用USB调试。"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在生成错误报告…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享错误报告吗?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享错误报告…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"您的 IT 管理员希望获取错误报告,以便排查此设备的问题。报告可能会透露您设备上的应用和数据。"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒绝"</string>
<string name="select_input_method" msgid="8547250819326693584">"更改键盘"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"选择键盘"</string>
<string name="show_ime" msgid="2506087537466597099">"连接到实体键盘时使其在屏幕上保持显示状态"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供程序"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知助手"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"已激活VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g>已激活VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
@@ -1336,9 +1334,9 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"删除"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"要将音量调高到推荐水平以上吗?\n\n长时间保持高音量可能会损伤听力。"</string>
- <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持续按住双指即可启用无障碍功能。"</string>
- <string name="accessibility_enabled" msgid="1381972048564547685">"无障碍功能已启用。"</string>
- <string name="enable_accessibility_canceled" msgid="3833923257966635673">"已取消无障碍功能。"</string>
+ <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持续按住双指即可启用辅助功能。"</string>
+ <string name="accessibility_enabled" msgid="1381972048564547685">"辅助功能已启用。"</string>
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"已取消辅助功能。"</string>
<string name="user_switched" msgid="3768006783166984410">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
<string name="user_switching_message" msgid="2871009331809089783">"正在切换为<xliff:g id="NAME">%1$s</xliff:g>…"</string>
<string name="user_logging_out_message" msgid="8939524935808875155">"正在将<xliff:g id="NAME">%1$s</xliff:g>退出帐号…"</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
<string name="app_info" msgid="6856026610594615344">"应用信息"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index faa320d..35300d4 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"語音助手"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"已根據政策隱藏內容"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -1136,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"虛擬現實接聽器"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件供應商"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知小幫手"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN 已啟用。"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網絡。"</string>
@@ -1564,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
<string name="app_info" msgid="6856026610594615344">"應用程式資料"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index d6820db..946c5cc 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"語音小幫手"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"內容已依據政策隱藏"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"輕觸即可顯示更多選項。"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"輕觸即可停用 USB 偵錯。"</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在接收錯誤報告…"</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"您的 IT 管理員要求您提供錯誤報告,以便排解這個裝置發生的問題。報告可能會揭露裝置中的應用程式和相關資料。"</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"分享"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"拒絕"</string>
<string name="select_input_method" msgid="8547250819326693584">"變更鍵盤"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"選擇鍵盤"</string>
<string name="show_ime" msgid="2506087537466597099">"有連接的實體鍵盤時保持顯示"</string>
@@ -1140,8 +1135,11 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
+ <!-- no translation found for vr_listener_binding_label (4316591939343607306) -->
+ <skip />
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件提供者"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知小幫手"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"VPN 已啟用"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網路。"</string>
@@ -1568,4 +1566,8 @@
<string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
<string name="app_info" msgid="6856026610594615344">"應用程式資訊"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ed5ec7d2..6af695d 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -229,7 +229,6 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Isisekeli sezwi"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Khiya manje"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
<string name="notification_hidden_text" msgid="1135169301897151909">"Okuqukethwe kufihliwe"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Okuqukethwe kufihlwe inqubomgomo"</string>
<string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
@@ -1052,16 +1051,12 @@
<string name="usb_notification_message" msgid="7347368030849048437">"Thinta ukuze uthole ezinye izinketho."</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Ukulungisa iphutha le-USB kuxhunyiwe"</string>
<string name="adb_active_notification_message" msgid="1016654627626476142">"Thinta ukwenza ukuthi ukudibhaga kwe-USB kungasebenzi."</string>
- <!-- no translation found for taking_remote_bugreport_notification_title (6742483073875060934) -->
- <skip />
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Ithatha umbiko wesiphazamisi..."</string>
<string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Yabelana ngombiko wesiphazamisi?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Yabelana ngombiko wesiphazamisi..."</string>
- <!-- no translation found for share_remote_bugreport_notification_message_finished (8610614010660772643) -->
- <skip />
- <!-- no translation found for share_remote_bugreport_action (6249476773913384948) -->
- <skip />
- <!-- no translation found for decline_remote_bugreport_action (6230987241608770062) -->
- <skip />
+ <string name="share_remote_bugreport_notification_message_finished" msgid="8610614010660772643">"Umqondisi wakho we-IT ucele umbiko wesiphazamisi ukukusiza ukuxazulula inkinga kule divayisi. Izinhlelo zokusebenza nedatha ingabiwa."</string>
+ <string name="share_remote_bugreport_action" msgid="6249476773913384948">"YABELANA"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"YENQABA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Shintsha ikhibhodi"</string>
<string name="configure_input_methods" msgid="4769971288371946846">"Khetha amakhibhodi"</string>
<string name="show_ime" msgid="2506087537466597099">"Yigcine kusikrini ngenkathi kusebenza ikhibhodi ephathekayo"</string>
@@ -1140,8 +1135,10 @@
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Iphephadonga"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Shintsha iphephadonga"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Umlaleli wesaziso"</string>
+ <string name="vr_listener_binding_label" msgid="4316591939343607306">"Isilaleli se-VR"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Umhlinzeki wesimo"</string>
- <string name="notification_assistant_binding_label" msgid="909456055569102952">"Umsizi wesaziso"</string>
+ <!-- no translation found for notification_ranker_binding_label (774540592299064747) -->
+ <skip />
<string name="vpn_title" msgid="19615213552042827">"I-VPN isiyasebenza"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"i-VPN ivuswe ngu <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Thinta ukuze wengamele inethiwekhi."</string>
@@ -1568,4 +1565,8 @@
<string name="unpin_target" msgid="3556545602439143442">"Susa ukuphina"</string>
<string name="app_info" msgid="6856026610594615344">"Ulwazi lohlelo lokusebenza"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+ <!-- no translation found for audit_safemode_notification (6351827251856877200) -->
+ <skip />
+ <!-- no translation found for audit_safemode_notification_details (1860601176690176413) -->
+ <skip />
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7857107..ce5d07c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2440,9 +2440,13 @@
flag). -->
<bool name="config_forceWindowDrawsStatusBarBackground">true</bool>
- <!-- If set, this will force the navigation bar to always be drawn with an opaque
- background. -->
- <bool name="config_forceNavBarAlwaysOpaque">false</bool>
+ <!-- Controls the opacity of the navigation bar depending on the visibility of the
+ various workspace stacks.
+ 0 - Nav bar is always opaque when either the freeform stack or docked stack is visible.
+ 1 - Nav bar is always translucent when the freeform stack is visible, otherwise always
+ opaque.
+ -->
+ <integer name="config_navBarOpacityMode">0</integer>
<!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
<string translatable="false" name="config_defaultPictureInPictureBounds">"0 0 100 100"</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cad0e7b..5737380 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2394,7 +2394,7 @@
<java-symbol type="string" name="config_packagedKeyboardName" />
<java-symbol type="bool" name="config_forceWindowDrawsStatusBarBackground" />
- <java-symbol type="bool" name="config_forceNavBarAlwaysOpaque" />
+ <java-symbol type="integer" name="config_navBarOpacityMode" />
<java-symbol type="color" name="system_bar_background_semi_transparent" />
<!-- EditText suggestion popup. -->
diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index af2a944..bae4ecc 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -81,8 +81,7 @@
protected static final int DEFAULT_WAIT_POLL_TIME = 5 * 1000; // 5 seconds
protected static final int WAIT_FOR_DOWNLOAD_POLL_TIME = 1 * 1000; // 1 second
- protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 5 * 60 * 1000; // 5 minutes
- protected static final int MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME = 15 * 60 * 1000; // 15 minutes
+ protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 30 * 1000; // 30 seconds
protected static final int DOWNLOAD_TO_SYSTEM_CACHE = 1;
protected static final int DOWNLOAD_TO_DOWNLOAD_CACHE_DIR = 2;
@@ -970,7 +969,7 @@
protected void verifyInt(Cursor cursor, String columnName, int expected) {
int index = cursor.getColumnIndex(columnName);
int actual = cursor.getInt(index);
- assertEquals(expected, actual);
+ assertEquals(String.format("Expected = %d : Actual = %d", expected, actual), expected, actual);
}
/**
diff --git a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
index 7019980..78a3aa6 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
@@ -23,18 +23,18 @@
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.test.suitebuilder.annotation.LargeTest;
-
+import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.Suppress;
import com.google.mockwebserver.MockResponse;
import java.io.File;
+import java.util.concurrent.TimeoutException;
import java.util.Iterator;
import java.util.Set;
/**
* Integration tests of the DownloadManager API.
*/
-@Suppress // Failing.
public class DownloadManagerFunctionalTest extends DownloadManagerBaseTest {
private static final String TAG = "DownloadManagerFunctionalTest";
private final static String CACHE_DIR =
@@ -79,7 +79,11 @@
request.setTitle(DEFAULT_FILENAME);
long dlRequest = mDownloadManager.enqueue(request);
- waitForDownloadOrTimeout(dlRequest);
+ try {
+ waitForDownloadOrTimeout(dlRequest);
+ } catch (TimeoutException ex) {
+ // it is expected to timeout as download never finishes
+ }
Cursor cursor = getCursor(dlRequest);
try {
@@ -92,7 +96,7 @@
/**
* Test a basic download of a binary file 500k in size.
*/
- @LargeTest
+ @MediumTest
public void testBinaryDownloadToSystemCache() throws Exception {
int fileSize = 1024;
byte[] blobData = generateData(fileSize, DataType.BINARY);
@@ -105,7 +109,7 @@
/**
* Tests the basic downloading of a text file 300000 bytes in size.
*/
- @LargeTest
+ @MediumTest
public void testTextDownloadToSystemCache() throws Exception {
int fileSize = 1024;
byte[] blobData = generateData(fileSize, DataType.TEXT);
@@ -114,7 +118,7 @@
verifyDownload(dlRequest, blobData);
mDownloadManager.remove(dlRequest);
}
-
+
/**
* Helper to verify a standard single-file download from the mock server, and clean up after
* verification
@@ -135,9 +139,7 @@
verifyFileSize(pfd, fileSize);
verifyFileContents(pfd, fileData);
- int colIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
- String fileName = cursor.getString(colIndex);
- assertTrue(fileName.startsWith(CACHE_DIR));
+ assertTrue(new File(CACHE_DIR + "/" + DEFAULT_FILENAME).exists());
} finally {
pfd.close();
cursor.close();
@@ -147,7 +149,7 @@
/**
* Tests trying to download to SD card when the file with same name already exists.
*/
- @LargeTest
+ @MediumTest
public void testDownloadToExternal_fileExists() throws Exception {
File existentFile = createFileOnSD(null, 1, DataType.TEXT, null);
byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
@@ -161,7 +163,6 @@
Uri localUri = Uri.fromFile(existentFile);
request.setDestinationUri(localUri);
-
long dlRequest = mDownloadManager.enqueue(request);
// wait for the download to complete
@@ -181,7 +182,7 @@
/**
* Tests trying to download a file to SD card.
*/
- @LargeTest
+ @MediumTest
public void testDownloadToExternal() throws Exception {
String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
File downloadedFile = new File(localDownloadDirectory, DEFAULT_FILENAME);
@@ -216,7 +217,7 @@
/**
* Tests trying to download a file to the system partition.
*/
- @LargeTest
+ @MediumTest
public void testDownloadToProhibitedDirectory() throws Exception {
File downloadedFile = new File(PROHIBITED_DIRECTORY, DEFAULT_FILENAME);
try {
@@ -246,7 +247,7 @@
/**
* Tests that we get the correct download ID from the download notification.
*/
- @LargeTest
+ @MediumTest
public void testGetDownloadIdOnNotification() throws Exception {
byte[] blobData = generateData(3000, DataType.TEXT); // file size = 3000 bytes
@@ -264,7 +265,7 @@
/**
* Tests the download failure error after too many redirects (>5).
*/
- @LargeTest
+ @MediumTest
public void testErrorTooManyRedirects() throws Exception {
Uri uri = getServerUri(DEFAULT_FILENAME);
@@ -304,7 +305,7 @@
/**
* Tests that we can remove a download from the download manager.
*/
- @LargeTest
+ @MediumTest
public void testRemoveDownload() throws Exception {
int fileSize = 1024;
byte[] blobData = generateData(fileSize, DataType.BINARY);
@@ -324,7 +325,7 @@
/**
* Tests that we can set the title of a download.
*/
- @LargeTest
+ @MediumTest
public void testSetTitle() throws Exception {
int fileSize = 1024;
byte[] blobData = generateData(fileSize, DataType.BINARY);
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 5dae4a8..844eadb 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -44,6 +44,7 @@
import com.android.frameworks.coretests.R;
+import android.support.test.espresso.action.EspressoKey;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.KeyEvent;
@@ -172,6 +173,12 @@
onView(withId(R.id.textview)).check(hasSelection(""));
assertNoSelectionHandles();
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex("abc ghi.def".length()));
+
+ // Test undo returns to the original state.
+ onView(withId(R.id.textview)).perform(pressKey(
+ (new EspressoKey.Builder()).withCtrlPressed(true).withKeyCode(KeyEvent.KEYCODE_Z)
+ .build()));
+ onView(withId(R.id.textview)).check(matches(withText(text)));
}
@SmallTest
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index 0c20876..b512396 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -9,7 +9,7 @@
$(call all-java-files-under, src)
LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib
+LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index dc302c7..bcac6a1 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -88,242 +88,246 @@
</family>
<!-- fallback fonts -->
- <family variant="elegant">
+ <family lang="und-Arab" variant="elegant">
<font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font>
<font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Arab" variant="compact">
<font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
<font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
</family>
- <family>
+ <family lang="und-Ethi">
<font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
<font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
</family>
- <family>
+ <family lang="und-Hebr">
<font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
<font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Thai" variant="elegant">
<font weight="400" style="normal">NotoSansThai-Regular.ttf</font>
<font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Thai" variant="compact">
<font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
</family>
- <family>
+ <family lang="und-Armn">
<font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font>
<font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
</family>
- <family>
+ <!-- TODO: add Geok -->
+ <family lang="und-Geor">
<font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
<font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Deva" variant="elegant">
<font weight="400" style="normal">NotoSansDevanagari-Regular.ttf</font>
<font weight="700" style="normal">NotoSansDevanagari-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Deva" variant="compact">
<font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font>
</family>
- <!-- Gujarati should come after Devanagari -->
- <family variant="elegant">
+
+ <!-- All scripts of India should come after Devanagari, due to shared
+ danda characters.
+ -->
+ <family lang="und-Gujr" variant="elegant">
<font weight="400" style="normal">NotoSansGujarati-Regular.ttf</font>
<font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Gujr" variant="compact">
<font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
</family>
- <!-- Gurmukhi should come after Devanagari -->
- <family variant="elegant">
+ <family lang="und-Guru" variant="elegant">
<font weight="400" style="normal">NotoSansGurmukhi-Regular.ttf</font>
<font weight="700" style="normal">NotoSansGurmukhi-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Guru" variant="compact">
<font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Taml" variant="elegant">
<font weight="400" style="normal">NotoSansTamil-Regular.ttf</font>
<font weight="700" style="normal">NotoSansTamil-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Taml" variant="compact">
<font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Mlym" variant="elegant">
<font weight="400" style="normal">NotoSansMalayalam-Regular.ttf</font>
<font weight="700" style="normal">NotoSansMalayalam-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Mlym" variant="compact">
<font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Beng" variant="elegant">
<font weight="400" style="normal">NotoSansBengali-Regular.ttf</font>
<font weight="700" style="normal">NotoSansBengali-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Beng" variant="compact">
<font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Telu" variant="elegant">
<font weight="400" style="normal">NotoSansTelugu-Regular.ttf</font>
<font weight="700" style="normal">NotoSansTelugu-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Telu" variant="compact">
<font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Knda" variant="elegant">
<font weight="400" style="normal">NotoSansKannada-Regular.ttf</font>
<font weight="700" style="normal">NotoSansKannada-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Knda" variant="compact">
<font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Orya" variant="elegant">
<font weight="400" style="normal">NotoSansOriya-Regular.ttf</font>
<font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Orya" variant="compact">
<font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
</family>
- <family>
+
+ <family lang="und-Sinh">
<font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font>
<font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Khmr" variant="elegant">
<font weight="400" style="normal">NotoSansKhmer-Regular.ttf</font>
<font weight="700" style="normal">NotoSansKhmer-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Khmr" variant="compact">
<font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Laoo" variant="elegant">
<font weight="400" style="normal">NotoSansLao-Regular.ttf</font>
<font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Laoo" variant="compact">
<font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
</family>
- <family variant="elegant">
+ <family lang="und-Mymr" variant="elegant">
<font weight="400" style="normal">NotoSansMyanmar-Regular.ttf</font>
<font weight="700" style="normal">NotoSansMyanmar-Bold.ttf</font>
</family>
- <family variant="compact">
+ <family lang="und-Mymr" variant="compact">
<font weight="400" style="normal">NotoSansMyanmarUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font>
</family>
- <family>
+ <family lang="und-Thaa">
<font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
<font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
</family>
- <family>
+ <family lang="und-Cham">
<font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
<font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
</family>
- <family>
+ <family lang="und-Bali">
<font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Bamu">
<font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Batk">
<font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Bugi">
<font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Buhd">
<font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Cans">
<font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Cher">
<font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Copt">
<font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Glag">
<font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Hano">
<font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Java">
<font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Kali">
<font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Lepc">
<font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Limb">
<font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Lisu">
<font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Mand">
<font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Mtei">
<font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Talu">
<font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Nkoo">
<font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Olck">
<font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Rjng">
<font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Saur">
<font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Sund">
<font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Sylo">
<font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Syre">
<font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Tagb">
<font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Lana">
<font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Tavt">
<font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Tibt">
<font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Tfng">
<font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Vaii">
<font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Yiii">
<font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
</family>
<family>
@@ -332,6 +336,7 @@
<family lang="zh-Hans">
<font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
</family>
+ <!-- TODO: Add Bopo -->
<family lang="zh-Hant">
<font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
</family>
@@ -351,10 +356,10 @@
Tai Le and Mongolian are intentionally kept last, to make sure they don't override
the East Asian punctuation for Chinese.
-->
- <family>
+ <family lang="und-Tale">
<font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
</family>
- <family>
+ <family lang="und-Mong">
<font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
</family>
</familyset>
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index ca214ab..219bca8 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -35,6 +35,7 @@
import android.graphics.ColorFilter;
import android.graphics.Insets;
import android.graphics.Outline;
+import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Build;
@@ -307,7 +308,7 @@
@Override
public int getOpacity() {
- return mAnimatedVectorState.mVectorDrawable.getOpacity();
+ return PixelFormat.TRANSLUCENT;
}
@Override
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index f9208cd..7b1e62a 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -17,6 +17,7 @@
package android.graphics.drawable;
import android.annotation.ColorInt;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
@@ -51,6 +52,8 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* A Drawable with a color gradient for buttons, backgrounds, etc.
@@ -108,6 +111,11 @@
*/
public static final int RING = 3;
+ /** @hide */
+ @IntDef({RECTANGLE, OVAL, LINE, RING})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Shape {}
+
/**
* Gradient is linear (default.)
*/
@@ -123,6 +131,11 @@
*/
public static final int SWEEP_GRADIENT = 2;
+ /** @hide */
+ @IntDef({LINEAR_GRADIENT, RADIAL_GRADIENT, SWEEP_GRADIENT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GradientType {}
+
/** Radius is in pixels. */
private static final int RADIUS_TYPE_PIXELS = 0;
@@ -132,6 +145,11 @@
/** Radius is a fraction of the bounds size. */
private static final int RADIUS_TYPE_FRACTION_PARENT = 2;
+ /** @hide */
+ @IntDef({RADIUS_TYPE_PIXELS, RADIUS_TYPE_FRACTION, RADIUS_TYPE_FRACTION_PARENT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RadiusType {}
+
private static final float DEFAULT_INNER_RADIUS_RATIO = 3.0f;
private static final float DEFAULT_THICKNESS_RATIO = 9.0f;
@@ -404,7 +422,7 @@
*
* @see #mutate()
*/
- public void setShape(int shape) {
+ public void setShape(@Shape int shape) {
mRingPath = null;
mPathIsDirty = true;
mGradientState.setShape(shape);
@@ -412,6 +430,18 @@
}
/**
+ * Returns the type of shape used by this drawable, one of {@link #LINE},
+ * {@link #OVAL}, {@link #RECTANGLE} or {@link #RING}.
+ *
+ * @return the type of shape used by this drawable
+ * @see #setShape(int)
+ */
+ @Shape
+ public int getShape() {
+ return mGradientState.mShape;
+ }
+
+ /**
* Sets the type of gradient used by this drawable.
* <p>
* <strong>Note</strong>: changing this property will affect all instances
@@ -424,7 +454,7 @@
* @see #mutate()
* @see #getGradientType()
*/
- public void setGradientType(int gradient) {
+ public void setGradientType(@GradientType int gradient) {
mGradientState.setGradientType(gradient);
mGradientIsDirty = true;
invalidateSelf();
@@ -438,6 +468,7 @@
* @return the type of gradient used by this drawable
* @see #setGradientType(int)
*/
+ @GradientType
public int getGradientType() {
return mGradientState.mGradient;
}
@@ -534,7 +565,7 @@
* @see #mutate()
* @see #setLevel(int)
* @see #getLevel()
- * @see #isUseLevel()
+ * @see #getUseLevel()
*/
public void setUseLevel(boolean useLevel) {
mGradientState.mUseLevel = useLevel;
@@ -550,7 +581,7 @@
* {@code false} otherwise
* @see #setUseLevel(boolean)
*/
- public boolean isUseLevel() {
+ public boolean getUseLevel() {
return mGradientState.mUseLevel;
}
@@ -616,7 +647,8 @@
*/
@Nullable
public int[] getColors() {
- return mGradientState.mGradientColors.clone();
+ return mGradientState.mGradientColors == null ?
+ null : mGradientState.mGradientColors.clone();
}
@Override
@@ -848,7 +880,7 @@
* @see #mutate()
* @see #getColor
*/
- public void setColor(ColorStateList colorStateList) {
+ public void setColor(@Nullable ColorStateList colorStateList) {
mGradientState.setSolidColors(colorStateList);
final int color;
if (colorStateList == null) {
@@ -870,6 +902,7 @@
* @see #setColor(int)
* @see #setColor(ColorStateList)
*/
+ @Nullable
public ColorStateList getColor() {
return mGradientState.mSolidColors;
}
@@ -951,12 +984,13 @@
}
@Override
+ @Nullable
public ColorFilter getColorFilter() {
return mColorFilter;
}
@Override
- public void setColorFilter(ColorFilter colorFilter) {
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
if (colorFilter != mColorFilter) {
mColorFilter = colorFilter;
invalidateSelf();
@@ -964,14 +998,14 @@
}
@Override
- public void setTintList(ColorStateList tint) {
+ public void setTintList(@Nullable ColorStateList tint) {
mGradientState.mTint = tint;
mTintFilter = updateTintFilter(mTintFilter, tint, mGradientState.mTintMode);
invalidateSelf();
}
@Override
- public void setTintMode(PorterDuff.Mode tintMode) {
+ public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
mGradientState.mTintMode = tintMode;
mTintFilter = updateTintFilter(mTintFilter, mGradientState.mTint, tintMode);
invalidateSelf();
@@ -1543,7 +1577,7 @@
final TypedValue tv = a.peekValue(R.styleable.GradientDrawableGradient_gradientRadius);
if (tv != null) {
final float radius;
- final int radiusType;
+ final @RadiusType int radiusType;
if (tv.type == TypedValue.TYPE_FRACTION) {
radius = tv.getFraction(1.0f, 1.0f);
@@ -1624,7 +1658,9 @@
return false;
}
- if (!isOpaque(mFillPaint.getColor())) {
+ // Don't check opacity if we're using a gradient, as we've already
+ // checked the gradient opacity in mOpaqueOverShape.
+ if (mGradientState.mGradientColors == null && !isOpaque(mFillPaint.getColor())) {
return false;
}
@@ -1699,14 +1735,14 @@
final static class GradientState extends ConstantState {
public int mChangingConfigurations;
- public int mShape = RECTANGLE;
- public int mGradient = LINEAR_GRADIENT;
+ public @Shape int mShape = RECTANGLE;
+ public @GradientType int mGradient = LINEAR_GRADIENT;
public int mAngle = 0;
public Orientation mOrientation;
public ColorStateList mSolidColors;
public ColorStateList mStrokeColors;
- public int[] mGradientColors;
- public int[] mTempColors; // no need to copy
+ public @ColorInt int[] mGradientColors;
+ public @ColorInt int[] mTempColors; // no need to copy
public float[] mTempPositions; // no need to copy
public float[] mPositions;
public int mStrokeWidth = -1; // if >= 0 use stroking.
@@ -1727,7 +1763,7 @@
float mCenterX = 0.5f;
float mCenterY = 0.5f;
float mGradientRadius = 0.5f;
- int mGradientRadiusType = RADIUS_TYPE_PIXELS;
+ @RadiusType int mGradientRadiusType = RADIUS_TYPE_PIXELS;
boolean mUseLevel = false;
boolean mUseLevelForShape = true;
@@ -1933,12 +1969,12 @@
| (mTint != null ? mTint.getChangingConfigurations() : 0);
}
- public void setShape(int shape) {
+ public void setShape(@Shape int shape) {
mShape = shape;
computeOpacity();
}
- public void setGradientType(int gradient) {
+ public void setGradientType(@GradientType int gradient) {
mGradient = gradient;
}
@@ -1947,13 +1983,13 @@
mCenterY = y;
}
- public void setGradientColors(int[] colors) {
+ public void setGradientColors(@Nullable int[] colors) {
mGradientColors = colors;
mSolidColors = null;
computeOpacity();
}
- public void setSolidColors(ColorStateList colors) {
+ public void setSolidColors(@Nullable ColorStateList colors) {
mGradientColors = null;
mSolidColors = colors;
computeOpacity();
@@ -1984,7 +2020,8 @@
&& mRadiusArray == null;
}
- public void setStroke(int width, ColorStateList colors, float dashWidth, float dashGap) {
+ public void setStroke(int width, @Nullable ColorStateList colors, float dashWidth,
+ float dashGap) {
mStrokeWidth = width;
mStrokeColors = colors;
mStrokeDashWidth = dashWidth;
@@ -2012,7 +2049,7 @@
mHeight = height;
}
- public void setGradientRadius(float gradientRadius, int type) {
+ public void setGradientRadius(float gradientRadius, @RadiusType int type) {
mGradientRadius = gradientRadius;
mGradientRadiusType = type;
}
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 0de4c2c..51221b4 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -627,6 +627,11 @@
return this;
}
+ /** @hide */
+ public boolean hasTint() {
+ return (mTintList != null) || (mTintMode != DEFAULT_TINT_MODE);
+ }
+
/**
* Create an Icon pointing to an image file specified by path.
*
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 9e0f1b4..44a91fe 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -364,7 +364,9 @@
@Override
public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
+ // We can't tell whether the drawable is fully opaque unless we examine all the pixels,
+ // but we could tell it is transparent if the root alpha is 0.
+ return getAlpha() == 0 ? PixelFormat.TRANSPARENT : PixelFormat.TRANSLUCENT;
}
@Override
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 6813c89..05596f0 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -35,6 +35,8 @@
#include <android/configuration.h>
+#include <memory>
+
namespace android {
/**
@@ -1876,9 +1878,30 @@
struct Entry;
struct Package;
struct PackageGroup;
- struct bag_set;
typedef Vector<Type*> TypeList;
+ struct bag_set {
+ size_t numAttrs; // number in array
+ size_t availAttrs; // total space in array
+ uint32_t typeSpecFlags;
+ // Followed by 'numAttr' bag_entry structures.
+ };
+
+ /**
+ * Configuration dependent cached data. This must be cleared when the configuration is
+ * changed (setParameters).
+ */
+ struct TypeCacheEntry {
+ TypeCacheEntry() : cachedBags(NULL) {}
+
+ // Computed attribute bags for this type.
+ bag_set** cachedBags;
+
+ // Pre-filtered list of configurations (per asset path) that match the parameters set on this
+ // ResTable.
+ Vector<std::shared_ptr<Vector<const ResTable_type*>>> filteredConfigs;
+ };
+
status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false);
@@ -1900,6 +1923,13 @@
mutable Mutex mLock;
+ // Mutex that controls access to the list of pre-filtered configurations
+ // to check when looking up entries.
+ // When iterating over a bag, the mLock mutex is locked. While mLock is locked,
+ // we do resource lookups.
+ // Mutex is not reentrant, so we must use a different lock than mLock.
+ mutable Mutex mFilteredConfigLock;
+
status_t mError;
ResTable_config mParams;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index bf6ff11..52fe973 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -25,6 +25,7 @@
#include <string.h>
#include <limits>
+#include <memory>
#include <type_traits>
#include <androidfw/ByteBucketArray.h>
@@ -3193,7 +3194,6 @@
, name(_name)
, id(_id)
, largestTypeId(0)
- , bags(NULL)
, dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
, isSystemAsset(_isSystemAsset)
{ }
@@ -3220,36 +3220,41 @@
}
}
+ /**
+ * Clear all cache related data that depends on parameters/configuration.
+ * This includes the bag caches and filtered types.
+ */
void clearBagCache() {
- if (bags) {
+ for (size_t i = 0; i < typeCacheEntries.size(); i++) {
if (kDebugTableNoisy) {
- printf("bags=%p\n", bags);
+ printf("type=%zu\n", i);
}
- for (size_t i = 0; i < bags->size(); i++) {
+ const TypeList& typeList = types[i];
+ if (!typeList.isEmpty()) {
+ TypeCacheEntry& cacheEntry = typeCacheEntries.editItemAt(i);
+
+ // Reset the filtered configurations.
+ cacheEntry.filteredConfigs.clear();
+
+ bag_set** typeBags = cacheEntry.cachedBags;
if (kDebugTableNoisy) {
- printf("type=%zu\n", i);
+ printf("typeBags=%p\n", typeBags);
}
- const TypeList& typeList = types[i];
- if (!typeList.isEmpty()) {
- bag_set** typeBags = bags->get(i);
+
+ if (typeBags) {
+ const size_t N = typeList[0]->entryCount;
if (kDebugTableNoisy) {
- printf("typeBags=%p\n", typeBags);
+ printf("type->entryCount=%zu\n", N);
}
- if (typeBags) {
- const size_t N = typeList[0]->entryCount;
- if (kDebugTableNoisy) {
- printf("type->entryCount=%zu\n", N);
+ for (size_t j = 0; j < N; j++) {
+ if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF) {
+ free(typeBags[j]);
}
- for (size_t j = 0; j < N; j++) {
- if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
- free(typeBags[j]);
- }
- free(typeBags);
}
+ free(typeBags);
+ cacheEntry.cachedBags = NULL;
}
}
- delete bags;
- bags = NULL;
}
}
@@ -3277,9 +3282,11 @@
uint8_t largestTypeId;
- // Computed attribute bags, first indexed by the type and second
- // by the entry in that type.
- ByteBucketArray<bag_set**>* bags;
+ // Cached objects dependent on the parameters/configuration of this ResTable.
+ // Gets cleared whenever the parameters/configuration changes.
+ // These are stored here in a parallel structure because the data in `types` may
+ // be shared by other ResTable's (framework resources are shared this way).
+ ByteBucketArray<TypeCacheEntry> typeCacheEntries;
// The table mapping dynamic references to resolved references for
// this package group.
@@ -3293,14 +3300,6 @@
const bool isSystemAsset;
};
-struct ResTable::bag_set
-{
- size_t numAttrs; // number in array
- size_t availAttrs; // total space in array
- uint32_t typeSpecFlags;
- // Followed by 'numAttr' bag_entry structures.
-};
-
ResTable::Theme::Theme(const ResTable& table)
: mTable(table)
, mTypeSpecFlags(0)
@@ -4192,39 +4191,32 @@
}
// First see if we've already computed this bag...
- if (grp->bags) {
- bag_set** typeSet = grp->bags->get(t);
- if (typeSet) {
- bag_set* set = typeSet[e];
- if (set) {
- if (set != (bag_set*)0xFFFFFFFF) {
- if (outTypeSpecFlags != NULL) {
- *outTypeSpecFlags = set->typeSpecFlags;
- }
- *outBag = (bag_entry*)(set+1);
- if (kDebugTableSuperNoisy) {
- ALOGI("Found existing bag for: 0x%x\n", resID);
- }
- return set->numAttrs;
+ TypeCacheEntry& cacheEntry = grp->typeCacheEntries.editItemAt(t);
+ bag_set** typeSet = cacheEntry.cachedBags;
+ if (typeSet) {
+ bag_set* set = typeSet[e];
+ if (set) {
+ if (set != (bag_set*)0xFFFFFFFF) {
+ if (outTypeSpecFlags != NULL) {
+ *outTypeSpecFlags = set->typeSpecFlags;
}
- ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
- resID);
- return BAD_INDEX;
+ *outBag = (bag_entry*)(set+1);
+ if (kDebugTableSuperNoisy) {
+ ALOGI("Found existing bag for: 0x%x\n", resID);
+ }
+ return set->numAttrs;
}
+ ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
+ resID);
+ return BAD_INDEX;
}
}
// Bag not found, we need to compute it!
- if (!grp->bags) {
- grp->bags = new ByteBucketArray<bag_set**>();
- if (!grp->bags) return NO_MEMORY;
- }
-
- bag_set** typeSet = grp->bags->get(t);
if (!typeSet) {
typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
if (!typeSet) return NO_MEMORY;
- grp->bags->set(t, typeSet);
+ cacheEntry.cachedBags = typeSet;
}
// Mark that we are currently working on this one.
@@ -4430,18 +4422,56 @@
void ResTable::setParameters(const ResTable_config* params)
{
- mLock.lock();
+ AutoMutex _lock(mLock);
+ AutoMutex _lock2(mFilteredConfigLock);
+
if (kDebugTableGetEntry) {
ALOGI("Setting parameters: %s\n", params->toString().string());
}
mParams = *params;
- for (size_t i=0; i<mPackageGroups.size(); i++) {
+ for (size_t p = 0; p < mPackageGroups.size(); p++) {
+ PackageGroup* packageGroup = mPackageGroups.editItemAt(p);
if (kDebugTableNoisy) {
- ALOGI("CLEARING BAGS FOR GROUP %zu!", i);
+ ALOGI("CLEARING BAGS FOR GROUP %zu!", p);
}
- mPackageGroups[i]->clearBagCache();
+ packageGroup->clearBagCache();
+
+ // Find which configurations match the set of parameters. This allows for a much
+ // faster lookup in getEntry() if the set of values is narrowed down.
+ for (size_t t = 0; t < packageGroup->types.size(); t++) {
+ if (packageGroup->types[t].isEmpty()) {
+ continue;
+ }
+
+ TypeList& typeList = packageGroup->types.editItemAt(t);
+
+ // Retrieve the cache entry for this type.
+ TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries.editItemAt(t);
+
+ for (size_t ts = 0; ts < typeList.size(); ts++) {
+ Type* type = typeList.editItemAt(ts);
+
+ std::shared_ptr<Vector<const ResTable_type*>> newFilteredConfigs =
+ std::make_shared<Vector<const ResTable_type*>>();
+
+ for (size_t ti = 0; ti < type->configs.size(); ti++) {
+ ResTable_config config;
+ config.copyFromDtoH(type->configs[ti]->config);
+
+ if (config.match(mParams)) {
+ newFilteredConfigs->add(type->configs[ti]);
+ }
+ }
+
+ if (kDebugTableNoisy) {
+ ALOGD("Updating pkg=%zu type=%zu with %zu filtered configs",
+ p, t, newFilteredConfigs->size());
+ }
+
+ cacheEntry.filteredConfigs.add(newFilteredConfigs);
+ }
+ }
}
- mLock.unlock();
}
void ResTable::getParameters(ResTable_config* params) const
@@ -5974,9 +6004,32 @@
specFlags = -1;
}
- const size_t numConfigs = typeSpec->configs.size();
+ const Vector<const ResTable_type*>* candidateConfigs = &typeSpec->configs;
+
+ std::shared_ptr<Vector<const ResTable_type*>> filteredConfigs;
+ if (config && memcmp(&mParams, config, sizeof(mParams)) == 0) {
+ // Grab the lock first so we can safely get the current filtered list.
+ AutoMutex _lock(mFilteredConfigLock);
+
+ // This configuration is equal to the one we have previously cached for,
+ // so use the filtered configs.
+
+ const TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries[typeIndex];
+ if (i < cacheEntry.filteredConfigs.size()) {
+ if (cacheEntry.filteredConfigs[i]) {
+ // Grab a reference to the shared_ptr so it doesn't get destroyed while
+ // going through this list.
+ filteredConfigs = cacheEntry.filteredConfigs[i];
+
+ // Use this filtered list.
+ candidateConfigs = filteredConfigs.get();
+ }
+ }
+ }
+
+ const size_t numConfigs = candidateConfigs->size();
for (size_t c = 0; c < numConfigs; c++) {
- const ResTable_type* const thisType = typeSpec->configs[c];
+ const ResTable_type* const thisType = candidateConfigs->itemAt(c);
if (thisType == NULL) {
continue;
}
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index dcfe91e..7cd7fb5 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -282,4 +282,46 @@
testU16StringToInt(u"0x1ffffffff", 0U, false, true);
}
+TEST(ResTableTest, ShareButDontModifyResTable) {
+ ResTable sharedTable;
+ ASSERT_EQ(NO_ERROR, sharedTable.add(basic_arsc, basic_arsc_len));
+
+ ResTable_config param;
+ memset(¶m, 0, sizeof(param));
+ param.language[0] = 'v';
+ param.language[1] = 's';
+ sharedTable.setParameters(¶m);
+
+ // Check that we get the default value for @integer:number1
+ Res_value val;
+ ssize_t block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+ ASSERT_EQ(uint32_t(600), val.data);
+
+ // Create a new table that shares the entries of the shared table.
+ ResTable table;
+ ASSERT_EQ(NO_ERROR, table.add(&sharedTable, false));
+
+ // Set a new configuration on the new table.
+ memset(¶m, 0, sizeof(param));
+ param.language[0] = 's';
+ param.language[1] = 'v';
+ param.country[0] = 'S';
+ param.country[1] = 'E';
+ table.setParameters(¶m);
+
+ // Check that we get a new value in the new table.
+ block = table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+ ASSERT_EQ(uint32_t(400), val.data);
+
+ // Check that we still get the old value in the shared table.
+ block = sharedTable.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG);
+ ASSERT_GE(block, 0);
+ ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
+ ASSERT_EQ(uint32_t(600), val.data);
}
+
+} // namespace
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index aaac740..6694dd0 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -46,7 +46,7 @@
namespace integer {
enum {
- number1 = 0x7f040000, // default, sv
+ number1 = 0x7f040000, // default, sv, vs
number2 = 0x7f040001, // default
test3 = 0x7f090000, // default (in feature)
diff --git a/libs/androidfw/tests/data/basic/basic_arsc.h b/libs/androidfw/tests/data/basic/basic_arsc.h
index 13ab4fa..e497401 100644
--- a/libs/androidfw/tests/data/basic/basic_arsc.h
+++ b/libs/androidfw/tests/data/basic/basic_arsc.h
@@ -1,5 +1,5 @@
unsigned char basic_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0x68, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0x0c, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
@@ -16,7 +16,7 @@
0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00,
0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01,
- 0xa0, 0x06, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x44, 0x07, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00,
0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
@@ -73,68 +73,81 @@
0x41, 0x00, 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x31, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00,
- 0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10,
- 0x05, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x24, 0x00, 0x00,
- 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x24, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+ 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+ 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x4c, 0x00, 0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
- 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x4c, 0x00, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x06, 0x7f, 0x01, 0x02, 0x44, 0x00, 0x5c, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+ 0xc8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x7f, 0x01, 0x02, 0x4c, 0x00,
+ 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x90, 0x01, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x44, 0x00, 0x90, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x58, 0x02, 0x00, 0x00,
+ 0x01, 0x02, 0x4c, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+ 0x90, 0x01, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x98, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -146,16 +159,17 @@
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x7f, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x2c, 0x01, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
- 0x7c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+ 0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,
- 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02,
+ 0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02,
+ 0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00
};
-unsigned int basic_arsc_len = 1896;
+unsigned int basic_arsc_len = 2060;
diff --git a/libs/androidfw/tests/data/basic/res/values-vs/values.xml b/libs/androidfw/tests/data/basic/res/values-vs/values.xml
new file mode 100644
index 0000000..4a5a640
--- /dev/null
+++ b/libs/androidfw/tests/data/basic/res/values-vs/values.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources>
+ <integer name="number1">600</integer>
+</resources>
diff --git a/libs/androidfw/tests/data/basic/split_de_fr_arsc.h b/libs/androidfw/tests/data/basic/split_de_fr_arsc.h
index b742d28..a2aa598 100644
--- a/libs/androidfw/tests/data/basic/split_de_fr_arsc.h
+++ b/libs/androidfw/tests/data/basic/split_de_fr_arsc.h
@@ -1,5 +1,5 @@
unsigned char split_de_fr_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0xf4, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
@@ -10,7 +10,7 @@
0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00,
0x61, 0x00, 0x69, 0x00, 0x20, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00,
0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x61, 0x00, 0x69, 0x00, 0x20, 0x00,
- 0x32, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x5c, 0x03, 0x00, 0x00,
+ 0x32, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x6c, 0x03, 0x00, 0x00,
0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00,
0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00,
0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00,
@@ -57,30 +57,32 @@
0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00,
- 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+ 0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x64, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00,
+ 0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
- 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
- 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0x61, 0x74, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
+ 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
};
-unsigned int split_de_fr_arsc_len = 996;
+unsigned int split_de_fr_arsc_len = 1012;
diff --git a/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h
index e9fb7ea..0cc3915 100644
--- a/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h
+++ b/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h
@@ -1,10 +1,10 @@
unsigned char split_hdpi_v4_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0x08, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0x10, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x68, 0x00,
0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01,
- 0xd0, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0xd8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00,
0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00,
@@ -50,19 +50,20 @@
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x02, 0x44, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x4c, 0x00, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
};
-unsigned int split_hdpi_v4_arsc_len = 776;
+unsigned int split_hdpi_v4_arsc_len = 784;
diff --git a/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h
index 7835f71..d44ba96 100644
--- a/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h
+++ b/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h
@@ -1,10 +1,10 @@
unsigned char split_xhdpi_v4_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0x14, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x78, 0x00,
0x68, 0x00, 0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x20, 0x01, 0xd0, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x20, 0x01, 0xd8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00,
0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00,
0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00,
@@ -50,19 +50,20 @@
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x60, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x68, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
- 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned int split_xhdpi_v4_arsc_len = 780;
+unsigned int split_xhdpi_v4_arsc_len = 788;
diff --git a/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h
index f805db1..2f3f682 100644
--- a/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h
+++ b/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h
@@ -1,10 +1,10 @@
unsigned char split_xxhdpi_v4_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0x14, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x78, 0x00,
0x78, 0x00, 0x68, 0x00, 0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x20, 0x01, 0xd0, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x20, 0x01, 0xd8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00,
0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00,
0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00,
@@ -50,19 +50,20 @@
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x60, 0x00, 0x00, 0x00,
- 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
- 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4c, 0x00, 0x68, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
- 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00,
- 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned int split_xxhdpi_v4_arsc_len = 780;
+unsigned int split_xxhdpi_v4_arsc_len = 788;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 9a9a89b..936c7e8 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -253,6 +253,7 @@
ifeq (true, $(HWUI_NEW_OPS))
LOCAL_SRC_FILES += \
+ tests/unit/BakedOpDispatcherTests.cpp \
tests/unit/BakedOpStateTests.cpp \
tests/unit/FrameBuilderTests.cpp \
tests/unit/LeakCheckTests.cpp \
@@ -304,13 +305,13 @@
LOCAL_CFLAGS := \
$(hwui_cflags) \
-DHWUI_NULL_GPU
-LOCAL_C_INCLUDES += bionic/benchmarks/
LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_null_gpu
-LOCAL_STATIC_LIBRARIES := libbenchmark libbase
+LOCAL_STATIC_LIBRARIES := libgoogle-benchmark
LOCAL_SRC_FILES += \
$(hwui_test_common_src_files) \
+ tests/microbench/main.cpp \
tests/microbench/DisplayListCanvasBench.cpp \
tests/microbench/LinearAllocatorBench.cpp \
tests/microbench/PathParserBench.cpp \
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 98493d7..da5ecca 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -324,7 +324,7 @@
}
}
-void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const ClipBase* clip,
+void BakedOpRenderer::renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip,
const Glop& glop) {
prepareRender(dirtyBounds, clip);
mRenderState.render(glop, mRenderTarget.orthoMatrix);
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index 4b65255..1b4065a 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_HWUI_BAKED_OP_RENDERER_H
-#define ANDROID_HWUI_BAKED_OP_RENDERER_H
+#pragma once
#include "BakedOpState.h"
#include "Matrix.h"
@@ -41,6 +40,7 @@
*/
class BakedOpRenderer {
public:
+ typedef void (*GlopReceiver)(BakedOpRenderer&, const Rect*, const ClipBase*, const Glop&);
/**
* Position agnostic shadow lighting info. Used with all shadow ops in scene.
*/
@@ -54,8 +54,10 @@
uint8_t spotShadowAlpha;
};
- BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, const LightInfo& lightInfo)
- : mRenderState(renderState)
+ BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque,
+ const LightInfo& lightInfo)
+ : mGlopReceiver(DefaultGlopReceiver)
+ , mRenderState(renderState)
, mCaches(caches)
, mOpaque(opaque)
, mLightInfo(lightInfo) {
@@ -81,7 +83,9 @@
}
void renderFunctor(const FunctorOp& op, const BakedOpState& state);
- void renderGlop(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
+ void renderGlop(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop) {
+ mGlopReceiver(*this, dirtyBounds, clip, glop);
+ }
bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; }
void dirtyRenderTarget(const Rect& dirtyRect);
bool didDraw() const { return mHasDrawn; }
@@ -95,7 +99,14 @@
drawRects(ltrb, 4, paint);
}
void drawRects(const float* rects, int count, const SkPaint* paint);
+protected:
+ GlopReceiver mGlopReceiver;
private:
+ static void DefaultGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
+ const ClipBase* clip, const Glop& glop) {
+ renderer.renderGlopImpl(dirtyBounds, clip, glop);
+ }
+ void renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
void setViewport(uint32_t width, uint32_t height);
void clearColorBuffer(const Rect& clearRect);
void prepareRender(const Rect* dirtyBounds, const ClipBase* clip);
@@ -136,5 +147,3 @@
}; // namespace uirenderer
}; // namespace android
-
-#endif // ANDROID_HWUI_BAKED_OP_RENDERER_H
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index deab956..709156c 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -437,8 +437,16 @@
y = dy * dz;
}
+/**
+ * Set the contents of the rect to be the bounding rect around each of the corners, mapped by the
+ * matrix.
+ *
+ * NOTE: an empty rect to an arbitrary matrix isn't guaranteed to have an empty output, since that's
+ * important for conservative bounds estimation (e.g. rotate45Matrix.mapRect of Rect(0, 10) should
+ * result in non-empty.
+ */
void Matrix4::mapRect(Rect& r) const {
- if (isIdentity() || r.isEmpty()) return;
+ if (isIdentity()) return;
if (isSimple()) {
MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]);
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index d9fce9b..de4fa55 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -286,7 +286,8 @@
friend std::ostream& operator<<(std::ostream& os, const Rect& rect) {
if (rect.isEmpty()) {
- return os << "empty";
+ // Print empty, but continue, since empty rects may still have useful coordinate info
+ os << "(empty)";
}
if (rect.left == 0 && rect.top == 0) {
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index b317c12..06b68d1 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
#include "DisplayList.h"
#if HWUI_NEW_OPS
@@ -23,7 +23,6 @@
#include "DisplayListCanvas.h"
#endif
#include "tests/common/TestUtils.h"
-#include "tests/microbench/MicroBench.h"
using namespace android;
using namespace android::uirenderer;
@@ -34,74 +33,64 @@
typedef DisplayListCanvas TestCanvas;
#endif
-BENCHMARK_NO_ARG(BM_DisplayList_alloc);
-void BM_DisplayList_alloc::Run(int iters) {
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
+void BM_DisplayList_alloc(benchmark::State& benchState) {
+ while (benchState.KeepRunning()) {
auto displayList = new DisplayList();
- MicroBench::DoNotOptimize(displayList);
+ benchmark::DoNotOptimize(displayList);
delete displayList;
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_DisplayList_alloc);
-BENCHMARK_NO_ARG(BM_DisplayList_alloc_theoretical);
-void BM_DisplayList_alloc_theoretical::Run(int iters) {
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
+void BM_DisplayList_alloc_theoretical(benchmark::State& benchState) {
+ while (benchState.KeepRunning()) {
auto displayList = new char[sizeof(DisplayList)];
- MicroBench::DoNotOptimize(displayList);
+ benchmark::DoNotOptimize(displayList);
delete[] displayList;
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_DisplayList_alloc_theoretical);
-BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_empty);
-void BM_DisplayListCanvas_record_empty::Run(int iters) {
+void BM_DisplayListCanvas_record_empty(benchmark::State& benchState) {
TestCanvas canvas(100, 100);
delete canvas.finishRecording();
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
+ while (benchState.KeepRunning()) {
canvas.resetRecording(100, 100);
- MicroBench::DoNotOptimize(&canvas);
+ benchmark::DoNotOptimize(&canvas);
delete canvas.finishRecording();
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_DisplayListCanvas_record_empty);
-BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_saverestore);
-void BM_DisplayListCanvas_record_saverestore::Run(int iters) {
+void BM_DisplayListCanvas_record_saverestore(benchmark::State& benchState) {
TestCanvas canvas(100, 100);
delete canvas.finishRecording();
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
+ while (benchState.KeepRunning()) {
canvas.resetRecording(100, 100);
canvas.save(SaveFlags::MatrixClip);
canvas.save(SaveFlags::MatrixClip);
- MicroBench::DoNotOptimize(&canvas);
+ benchmark::DoNotOptimize(&canvas);
canvas.restore();
canvas.restore();
delete canvas.finishRecording();
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_DisplayListCanvas_record_saverestore);
-BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_translate);
-void BM_DisplayListCanvas_record_translate::Run(int iters) {
+void BM_DisplayListCanvas_record_translate(benchmark::State& benchState) {
TestCanvas canvas(100, 100);
delete canvas.finishRecording();
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
+ while (benchState.KeepRunning()) {
canvas.resetRecording(100, 100);
canvas.scale(10, 10);
- MicroBench::DoNotOptimize(&canvas);
+ benchmark::DoNotOptimize(&canvas);
delete canvas.finishRecording();
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_DisplayListCanvas_record_translate);
/**
* Simulate a simple view drawing a background, overlapped by an image.
@@ -109,16 +98,14 @@
* Note that the recording commands are intentionally not perfectly efficient, as the
* View system frequently produces unneeded save/restores.
*/
-BENCHMARK_NO_ARG(BM_DisplayListCanvas_record_simpleBitmapView);
-void BM_DisplayListCanvas_record_simpleBitmapView::Run(int iters) {
+void BM_DisplayListCanvas_record_simpleBitmapView(benchmark::State& benchState) {
TestCanvas canvas(100, 100);
delete canvas.finishRecording();
SkPaint rectPaint;
SkBitmap iconBitmap = TestUtils::createSkBitmap(80, 80);
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
+ while (benchState.KeepRunning()) {
canvas.resetRecording(100, 100);
{
canvas.save(SaveFlags::MatrixClip);
@@ -131,11 +118,11 @@
canvas.drawBitmap(iconBitmap, 0, 0, nullptr);
canvas.restore();
}
- MicroBench::DoNotOptimize(&canvas);
+ benchmark::DoNotOptimize(&canvas);
delete canvas.finishRecording();
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_DisplayListCanvas_record_simpleBitmapView);
class NullClient: public CanvasStateClient {
void onViewportInitialized() override {}
@@ -143,48 +130,42 @@
GLuint getTargetFbo() const override { return 0; }
};
-BENCHMARK_NO_ARG(BM_CanvasState_saverestore);
-void BM_CanvasState_saverestore::Run(int iters) {
+void BM_CanvasState_saverestore(benchmark::State& benchState) {
NullClient client;
CanvasState state(client);
state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
+ while (benchState.KeepRunning()) {
state.save(SaveFlags::MatrixClip);
state.save(SaveFlags::MatrixClip);
- MicroBench::DoNotOptimize(&state);
+ benchmark::DoNotOptimize(&state);
state.restore();
state.restore();
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_CanvasState_saverestore);
-BENCHMARK_NO_ARG(BM_CanvasState_init);
-void BM_CanvasState_init::Run(int iters) {
+void BM_CanvasState_init(benchmark::State& benchState) {
NullClient client;
CanvasState state(client);
state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
+ while (benchState.KeepRunning()) {
state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
- MicroBench::DoNotOptimize(&state);
+ benchmark::DoNotOptimize(&state);
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_CanvasState_init);
-BENCHMARK_NO_ARG(BM_CanvasState_translate);
-void BM_CanvasState_translate::Run(int iters) {
+void BM_CanvasState_translate(benchmark::State& benchState) {
NullClient client;
CanvasState state(client);
state.initializeSaveStack(100, 100, 0, 0, 100, 100, Vector3());
- StartBenchmarkTiming();
- for (int i = 0; i < iters; ++i) {
+ while (benchState.KeepRunning()) {
state.translate(5, 5, 0);
- MicroBench::DoNotOptimize(&state);
+ benchmark::DoNotOptimize(&state);
state.translate(-5, -5, 0);
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_CanvasState_translate);
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index 7845eb4..7816f0f 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
#include "BakedOpState.h"
#include "BakedOpDispatcher.h"
@@ -27,7 +27,6 @@
#include "tests/common/TestScene.h"
#include "tests/common/TestUtils.h"
#include "Vector.h"
-#include "tests/microbench/MicroBench.h"
#include <vector>
@@ -62,38 +61,34 @@
return vec;
}
-BENCHMARK_NO_ARG(BM_FrameBuilder_defer);
-void BM_FrameBuilder_defer::Run(int iters) {
+void BM_FrameBuilder_defer(benchmark::State& state) {
auto nodes = createTestNodeList();
- StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+ while (state.KeepRunning()) {
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
nodes, sLightGeometry, nullptr);
- MicroBench::DoNotOptimize(&frameBuilder);
+ benchmark::DoNotOptimize(&frameBuilder);
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_FrameBuilder_defer);
-BENCHMARK_NO_ARG(BM_FrameBuilder_deferAndRender);
-void BM_FrameBuilder_deferAndRender::Run(int iters) {
- TestUtils::runOnRenderThread([this, iters](RenderThread& thread) {
+void BM_FrameBuilder_deferAndRender(benchmark::State& state) {
+ TestUtils::runOnRenderThread([&state](RenderThread& thread) {
auto nodes = createTestNodeList();
RenderState& renderState = thread.renderState();
Caches& caches = Caches::getInstance();
- StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+ while (state.KeepRunning()) {
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
nodes, sLightGeometry, nullptr);
BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
- MicroBench::DoNotOptimize(&renderer);
+ benchmark::DoNotOptimize(&renderer);
}
- StopBenchmarkTiming();
});
}
+BENCHMARK(BM_FrameBuilder_deferAndRender);
static std::vector<sp<RenderNode>> getSyncedSceneNodes(const char* sceneName) {
gDisplay = getBuiltInDisplay(); // switch to real display if present
@@ -113,47 +108,41 @@
return nodes;
}
-static void benchDeferScene(testing::Benchmark& benchmark, int iters, const char* sceneName) {
+static auto SCENES = {
+ "listview",
+};
+
+void BM_FrameBuilder_defer_scene(benchmark::State& state) {
+ const char* sceneName = *(SCENES.begin() + state.range_x());
+ state.SetLabel(sceneName);
auto nodes = getSyncedSceneNodes(sceneName);
- benchmark.StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+ while (state.KeepRunning()) {
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
nodes, sLightGeometry, nullptr);
- MicroBench::DoNotOptimize(&frameBuilder);
+ benchmark::DoNotOptimize(&frameBuilder);
}
- benchmark.StopBenchmarkTiming();
}
+BENCHMARK(BM_FrameBuilder_defer_scene)->DenseRange(0, SCENES.size() - 1);
-static void benchDeferAndRenderScene(testing::Benchmark& benchmark,
- int iters, const char* sceneName) {
- TestUtils::runOnRenderThread([&benchmark, iters, sceneName](RenderThread& thread) {
+void BM_FrameBuilder_deferAndRender_scene(benchmark::State& state) {
+ TestUtils::runOnRenderThread([&state](RenderThread& thread) {
+ const char* sceneName = *(SCENES.begin() + state.range_x());
+ state.SetLabel(sceneName);
auto nodes = getSyncedSceneNodes(sceneName);
RenderState& renderState = thread.renderState();
Caches& caches = Caches::getInstance();
- benchmark.StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+ while (state.KeepRunning()) {
FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w, gDisplay.h,
nodes, sLightGeometry, nullptr);
BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
- MicroBench::DoNotOptimize(&renderer);
+ benchmark::DoNotOptimize(&renderer);
}
- benchmark.StopBenchmarkTiming();
});
}
-
-BENCHMARK_NO_ARG(BM_FrameBuilder_listview_defer);
-void BM_FrameBuilder_listview_defer::Run(int iters) {
- benchDeferScene(*this, iters, "listview");
-}
-
-BENCHMARK_NO_ARG(BM_FrameBuilder_listview_deferAndRender);
-void BM_FrameBuilder_listview_deferAndRender::Run(int iters) {
- benchDeferAndRenderScene(*this, iters, "listview");
-}
-
+BENCHMARK(BM_FrameBuilder_deferAndRender_scene)->DenseRange(0, SCENES.size() - 1);
diff --git a/libs/hwui/tests/microbench/LinearAllocatorBench.cpp b/libs/hwui/tests/microbench/LinearAllocatorBench.cpp
index 28513e4..3c0a6c5 100644
--- a/libs/hwui/tests/microbench/LinearAllocatorBench.cpp
+++ b/libs/hwui/tests/microbench/LinearAllocatorBench.cpp
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
-#include "tests/microbench/MicroBench.h"
#include "utils/LinearAllocator.h"
#include <vector>
@@ -24,30 +23,26 @@
using namespace android;
using namespace android::uirenderer;
-BENCHMARK_NO_ARG(BM_LinearStdAllocator_vectorBaseline);
-void BM_LinearStdAllocator_vectorBaseline::Run(int iters) {
- StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+static void BM_LinearStdAllocator_vectorBaseline(benchmark::State& state) {
+ while (state.KeepRunning()) {
std::vector<char> v;
for (int j = 0; j < 200; j++) {
v.push_back(j);
}
- MicroBench::DoNotOptimize(&v);
+ benchmark::DoNotOptimize(&v);
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_LinearStdAllocator_vectorBaseline);
-BENCHMARK_NO_ARG(BM_LinearStdAllocator_vector);
-void BM_LinearStdAllocator_vector::Run(int iters) {
- StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+static void BM_LinearStdAllocator_vector(benchmark::State& state) {
+ while (state.KeepRunning()) {
LinearAllocator la;
LinearStdAllocator<void*> stdAllocator(la);
std::vector<char, LinearStdAllocator<char> > v(stdAllocator);
for (int j = 0; j < 200; j++) {
v.push_back(j);
}
- MicroBench::DoNotOptimize(&v);
+ benchmark::DoNotOptimize(&v);
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_LinearStdAllocator_vector);
diff --git a/libs/hwui/tests/microbench/MicroBench.h b/libs/hwui/tests/microbench/MicroBench.h
deleted file mode 100644
index f05e92c..0000000
--- a/libs/hwui/tests/microbench/MicroBench.h
+++ /dev/null
@@ -1,35 +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.
- */
-#ifndef MICROBENCH_MICROBENCH_H
-#define MICROBENCH_MICROBENCH_H
-
-namespace android {
-namespace uirenderer {
-
-#define NO_INLINE __attribute__ ((noinline))
-
-class MicroBench {
-public:
- template <class Tp>
- static inline void DoNotOptimize(Tp const& value) {
- asm volatile("" : "+rm" (const_cast<Tp&>(value)));
- }
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* MICROBENCH_MICROBENCH_H */
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index bd742c6..4186539 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
#include "PathParser.h"
#include "VectorDrawable.h"
@@ -26,26 +26,26 @@
static const char* sPathString = "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10";
-BENCHMARK_NO_ARG(BM_PathParser_parseStringPathForSkPath);
-void BM_PathParser_parseStringPathForSkPath::Run(int iter) {
+void BM_PathParser_parseStringPathForSkPath(benchmark::State& state) {
SkPath skPath;
size_t length = strlen(sPathString);
PathParser::ParseResult result;
- StartBenchmarkTiming();
- for (int i = 0; i < iter; i++) {
+ while (state.KeepRunning()) {
PathParser::parseStringForSkPath(&skPath, &result, sPathString, length);
+ benchmark::DoNotOptimize(&result);
+ benchmark::DoNotOptimize(&skPath);
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_PathParser_parseStringPathForSkPath);
-BENCHMARK_NO_ARG(BM_PathParser_parseStringPathForPathData);
-void BM_PathParser_parseStringPathForPathData::Run(int iter) {
+void BM_PathParser_parseStringPathForPathData(benchmark::State& state) {
size_t length = strlen(sPathString);
PathData outData;
PathParser::ParseResult result;
- StartBenchmarkTiming();
- for (int i = 0; i < iter; i++) {
+ while (state.KeepRunning()) {
PathParser::getPathDataFromString(&outData, &result, sPathString, length);
+ benchmark::DoNotOptimize(&result);
+ benchmark::DoNotOptimize(&outData);
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_PathParser_parseStringPathForPathData);
diff --git a/libs/hwui/tests/microbench/ShadowBench.cpp b/libs/hwui/tests/microbench/ShadowBench.cpp
index 98ec4d9..a0fc6e8 100644
--- a/libs/hwui/tests/microbench/ShadowBench.cpp
+++ b/libs/hwui/tests/microbench/ShadowBench.cpp
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
#include "Matrix.h"
#include "Rect.h"
#include "Vector.h"
#include "VertexBuffer.h"
#include "TessellationCache.h"
-#include "tests/microbench/MicroBench.h"
#include <SkPath.h>
@@ -78,39 +77,35 @@
testData.lightRadius, *ambient, *spot);
}
-BENCHMARK_NO_ARG(BM_TessellateShadows_roundrect_opaque);
-void BM_TessellateShadows_roundrect_opaque::Run(int iters) {
+void BM_TessellateShadows_roundrect_opaque(benchmark::State& state) {
ShadowTestData shadowData;
createShadowTestData(&shadowData);
SkPath path;
path.addRoundRect(SkRect::MakeWH(100, 100), 5, 5);
- StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+ while (state.KeepRunning()) {
VertexBuffer ambient;
VertexBuffer spot;
tessellateShadows(shadowData, true, path, &ambient, &spot);
- MicroBench::DoNotOptimize(&ambient);
- MicroBench::DoNotOptimize(&spot);
+ benchmark::DoNotOptimize(&ambient);
+ benchmark::DoNotOptimize(&spot);
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_TessellateShadows_roundrect_opaque);
-BENCHMARK_NO_ARG(BM_TessellateShadows_roundrect_translucent);
-void BM_TessellateShadows_roundrect_translucent::Run(int iters) {
+void BM_TessellateShadows_roundrect_translucent(benchmark::State& state) {
ShadowTestData shadowData;
createShadowTestData(&shadowData);
SkPath path;
path.reset();
path.addRoundRect(SkRect::MakeLTRB(0, 0, 100, 100), 5, 5);
- StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+ while (state.KeepRunning()) {
std::unique_ptr<VertexBuffer> ambient(new VertexBuffer);
std::unique_ptr<VertexBuffer> spot(new VertexBuffer);
tessellateShadows(shadowData, false, path, ambient.get(), spot.get());
- MicroBench::DoNotOptimize(ambient.get());
- MicroBench::DoNotOptimize(spot.get());
+ benchmark::DoNotOptimize(ambient.get());
+ benchmark::DoNotOptimize(spot.get());
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_TessellateShadows_roundrect_translucent);
diff --git a/libs/hwui/tests/microbench/TaskManagerBench.cpp b/libs/hwui/tests/microbench/TaskManagerBench.cpp
index 0ea30e47..c6b9f3b 100644
--- a/libs/hwui/tests/microbench/TaskManagerBench.cpp
+++ b/libs/hwui/tests/microbench/TaskManagerBench.cpp
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-#include <benchmark/Benchmark.h>
+#include <benchmark/benchmark.h>
#include "thread/Task.h"
#include "thread/TaskManager.h"
#include "thread/TaskProcessor.h"
-#include "tests/microbench/MicroBench.h"
#include <vector>
@@ -39,55 +38,51 @@
}
};
-BENCHMARK_NO_ARG(BM_TaskManager_allocateTask);
-void BM_TaskManager_allocateTask::Run(int iters) {
+void BM_TaskManager_allocateTask(benchmark::State& state) {
std::vector<sp<TrivialTask> > tasks;
- tasks.reserve(iters);
+ tasks.reserve(state.max_iterations);
- StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+ while (state.KeepRunning()) {
tasks.emplace_back(new TrivialTask);
- MicroBench::DoNotOptimize(tasks.back());
+ benchmark::DoNotOptimize(tasks.back());
}
- StopBenchmarkTiming();
}
+BENCHMARK(BM_TaskManager_allocateTask);
-BENCHMARK_NO_ARG(BM_TaskManager_enqueueTask);
-void BM_TaskManager_enqueueTask::Run(int iters) {
+void BM_TaskManager_enqueueTask(benchmark::State& state) {
TaskManager taskManager;
sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
std::vector<sp<TrivialTask> > tasks;
- tasks.reserve(iters);
+ tasks.reserve(state.max_iterations);
- StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+ while (state.KeepRunning()) {
tasks.emplace_back(new TrivialTask);
- MicroBench::DoNotOptimize(tasks.back());
+ benchmark::DoNotOptimize(tasks.back());
processor->add(tasks.back());
}
- StopBenchmarkTiming();
for (sp<TrivialTask>& task : tasks) {
task->getResult();
}
}
+BENCHMARK(BM_TaskManager_enqueueTask);
-BENCHMARK_NO_ARG(BM_TaskManager_enqueueRunDeleteTask);
-void BM_TaskManager_enqueueRunDeleteTask::Run(int iters) {
+void BM_TaskManager_enqueueRunDeleteTask(benchmark::State& state) {
TaskManager taskManager;
sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
std::vector<sp<TrivialTask> > tasks;
- tasks.reserve(iters);
+ tasks.reserve(state.max_iterations);
- StartBenchmarkTiming();
- for (int i = 0; i < iters; i++) {
+ while (state.KeepRunning()) {
tasks.emplace_back(new TrivialTask);
- MicroBench::DoNotOptimize(tasks.back());
+ benchmark::DoNotOptimize(tasks.back());
processor->add(tasks.back());
}
+ state.ResumeTiming();
for (sp<TrivialTask>& task : tasks) {
- MicroBench::DoNotOptimize(task->getResult());
+ benchmark::DoNotOptimize(task->getResult());
}
tasks.clear();
- StopBenchmarkTiming();
+ state.PauseTiming();
}
+BENCHMARK(BM_TaskManager_enqueueRunDeleteTask);
diff --git a/libs/hwui/tests/microbench/main.cpp b/libs/hwui/tests/microbench/main.cpp
new file mode 100644
index 0000000..a0157bc
--- /dev/null
+++ b/libs/hwui/tests/microbench/main.cpp
@@ -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.
+ */
+
+#include <benchmark/benchmark.h>
+
+BENCHMARK_MAIN();
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
new file mode 100644
index 0000000..654ddc6
--- /dev/null
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <RecordedOp.h>
+#include <BakedOpDispatcher.h>
+#include <BakedOpRenderer.h>
+#include <tests/common/TestUtils.h>
+
+using namespace android::uirenderer;
+
+static BakedOpRenderer::LightInfo sLightInfo;
+static Rect sBaseClip(100, 100);
+
+class ValidatingBakedOpRenderer : public BakedOpRenderer {
+public:
+ ValidatingBakedOpRenderer(RenderState& renderState, std::function<void(const Glop& glop)> validator)
+ : BakedOpRenderer(Caches::getInstance(), renderState, true, sLightInfo)
+ , mValidator(validator) {
+ mGlopReceiver = ValidatingGlopReceiver;
+ }
+private:
+ static void ValidatingGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
+ const ClipBase* clip, const Glop& glop) {
+
+ auto vbor = reinterpret_cast<ValidatingBakedOpRenderer*>(&renderer);
+ vbor->mValidator(glop);
+ }
+ std::function<void(const Glop& glop)> mValidator;
+};
+
+typedef void (*BakedOpReceiver)(BakedOpRenderer&, const BakedOpState&);
+
+static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op,
+ std::function<void(const Glop& glop)> glopVerifier) {
+ // Create op, and wrap with basic state.
+ LinearAllocator allocator;
+ auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), sBaseClip);
+ auto state = BakedOpState::tryConstruct(allocator, *snapshot, *op);
+ ASSERT_NE(nullptr, state);
+
+ int glopCount = 0;
+ auto glopReceiver = [&glopVerifier, &glopCount] (const Glop& glop) {
+ ASSERT_EQ(glopCount++, 0) << "Only one Glop expected";
+ glopVerifier(glop);
+ };
+ ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver);
+
+ // Dispatch based on op type created, similar to Frame/LayerBuilder dispatch behavior
+#define X(Type) \
+ [](BakedOpRenderer& renderer, const BakedOpState& state) { \
+ BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \
+ },
+ static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
+#undef X
+ unmergedReceivers[op->opId](renderer, *state);
+ ASSERT_EQ(1, glopCount) << "Exactly one Glop expected";
+}
+
+RENDERTHREAD_TEST(BakedOpDispatcher, onArc_position) {
+ SkPaint strokePaint;
+ strokePaint.setStyle(SkPaint::kStroke_Style);
+ strokePaint.setStrokeWidth(4);
+ ArcOp op(Rect(10, 15, 20, 25), Matrix4::identity(), nullptr, &strokePaint, 0, 270, true);
+ testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
+ // validate glop produced by renderPathTexture (so texture, unit quad)
+ auto texture = glop.fill.texture.texture;
+ ASSERT_NE(nullptr, texture);
+ float expectedOffset = floor(4 * 1.5f + 0.5f);
+ EXPECT_EQ(expectedOffset, reinterpret_cast<PathTexture*>(texture)->offset)
+ << "Should see conservative offset from PathCache::computeBounds";
+ Rect expectedBounds(10, 15, 20, 25);
+ expectedBounds.outset(expectedOffset);
+ EXPECT_EQ(expectedBounds, glop.bounds) << "bounds outset by stroke 'offset'";
+ Matrix4 expectedModelView;
+ expectedModelView.loadTranslate(10 - expectedOffset, 15 - expectedOffset, 0);
+ expectedModelView.scale(10 + 2 * expectedOffset, 10 + 2 * expectedOffset, 1);
+ EXPECT_EQ(expectedModelView, glop.transform.modelView)
+ << "X and Y offsets, and scale both applied to model view";
+ });
+}
+
+RENDERTHREAD_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
+ SkPaint layerPaint;
+ layerPaint.setAlpha(128);
+ OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
+ LayerOp op(Rect(10, 10), Matrix4::identity(), nullptr, &layerPaint, &buffer);
+ testUnmergedGlopDispatch(renderThread, &op, [&renderThread] (const Glop& glop) {
+ // rect glop is dispatched with paint props applied
+ EXPECT_EQ(renderThread.renderState().meshState().getUnitQuadVBO(),
+ glop.mesh.vertices.bufferObject) << "Unit quad should be drawn";
+ EXPECT_EQ(nullptr, glop.fill.texture.texture) << "Should be no texture when layer is null";
+ EXPECT_FLOAT_EQ(128 / 255.0f, glop.fill.color.a) << "Rect quad should use op alpha";
+ });
+}
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 402a09c..ffcbf12 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -113,3 +113,21 @@
EXPECT_GT(lastLocation + 20, &v[0]);
}
+
+TEST(LsaVector, dtorCheck) {
+ LinearAllocator allocator;
+ LinearStdAllocator<void*> stdAllocator(allocator);
+
+ for (int size : {1, 2, 3, 500}) {
+ int destroyed = 0;
+ {
+ LsaVector<std::unique_ptr<TestUtils::SignalingDtor> > vector(stdAllocator);
+ for (int i = 0; i < size; i++) {
+ vector.emplace_back(new TestUtils::SignalingDtor(&destroyed));
+ }
+ EXPECT_EQ(0, destroyed);
+ EXPECT_EQ(size, (int) vector.size());
+ }
+ EXPECT_EQ(size, destroyed);
+ }
+}
diff --git a/libs/hwui/tests/unit/MatrixTests.cpp b/libs/hwui/tests/unit/MatrixTests.cpp
index da22637..eddab87 100644
--- a/libs/hwui/tests/unit/MatrixTests.cpp
+++ b/libs/hwui/tests/unit/MatrixTests.cpp
@@ -21,15 +21,30 @@
using namespace android::uirenderer;
-TEST(Matrix, mapRect) {
+TEST(Matrix, mapRect_emptyScaleSkew) {
// Skew, so we don't hit identity/translate/simple fast paths
- Matrix4 matrix;
- matrix.skew(0.1f, 0.1f);
+ Matrix4 scaleMatrix;
+ scaleMatrix.loadScale(10, 10, 1);
+ scaleMatrix.skew(0.1f, 0.1f);
// non-zero empty rect, so sorting x/y would make rect non-empty
- Rect empty(100, 100, -100, -100);
+ Rect empty(15, 20, 15, 100);
ASSERT_TRUE(empty.isEmpty());
- matrix.mapRect(empty);
- EXPECT_TRUE(empty.isEmpty())
- << "Empty rect should always remain empty, regardless of mapping.";
+ scaleMatrix.mapRect(empty);
+ EXPECT_EQ(Rect(170, 215, 250, 1015), empty);
+ EXPECT_FALSE(empty.isEmpty())
+ << "Empty 'line' rect doesn't remain empty when skewed.";
+}
+
+TEST(Matrix, mapRect_emptyRotate) {
+ // Skew, so we don't hit identity/translate/simple fast paths
+ Matrix4 skewMatrix;
+ skewMatrix.loadRotate(45);
+
+ // non-zero empty rect, so sorting x/y would make rect non-empty
+ Rect lineRect(0, 100);
+ ASSERT_TRUE(lineRect.isEmpty());
+ skewMatrix.mapRect(lineRect);
+ EXPECT_FALSE(lineRect.isEmpty())
+ << "Empty 'line' rect doesn't remain empty when rotated.";
}
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index 6a7801e..2af4790 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -16,6 +16,7 @@
package android.location;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -48,13 +49,19 @@
private double mDriftUncertaintyNanosPerSecond;
private int mHardwareClockDiscontinuityCount;
- GnssClock() {
+ /**
+ * @hide
+ */
+ @TestApi
+ public GnssClock() {
initialize();
}
/**
* Sets all contents to the values stored in the provided object.
+ * @hide
*/
+ @TestApi
public void set(GnssClock clock) {
mFlags = clock.mFlags;
mLeapSecond = clock.mLeapSecond;
@@ -70,7 +77,9 @@
/**
* Resets all the contents to its original state.
+ * @hide
*/
+ @TestApi
public void reset() {
initialize();
}
@@ -95,7 +104,9 @@
/**
* Sets the leap second associated with the clock's time.
+ * @hide
*/
+ @TestApi
public void setLeapSecond(int leapSecond) {
setFlag(HAS_LEAP_SECOND);
mLeapSecond = leapSecond;
@@ -103,7 +114,9 @@
/**
* Resets the leap second associated with the clock's time.
+ * @hide
*/
+ @TestApi
public void resetLeapSecond() {
resetFlag(HAS_LEAP_SECOND);
mLeapSecond = Integer.MIN_VALUE;
@@ -129,7 +142,9 @@
/**
* Sets the GNSS receiver internal clock in nanoseconds.
+ * @hide
*/
+ @TestApi
public void setTimeNanos(long timeNanos) {
mTimeNanos = timeNanos;
}
@@ -153,7 +168,9 @@
/**
* Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
+ * @hide
*/
+ @TestApi
public void setTimeUncertaintyNanos(double timeUncertaintyNanos) {
setFlag(HAS_TIME_UNCERTAINTY);
mTimeUncertaintyNanos = timeUncertaintyNanos;
@@ -161,7 +178,9 @@
/**
* Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
+ * @hide
*/
+ @TestApi
public void resetTimeUncertaintyNanos() {
resetFlag(HAS_TIME_UNCERTAINTY);
mTimeUncertaintyNanos = Double.NaN;
@@ -193,7 +212,9 @@
/**
* Sets the full bias in nanoseconds.
+ * @hide
*/
+ @TestApi
public void setFullBiasNanos(long value) {
setFlag(HAS_FULL_BIAS);
mFullBiasNanos = value;
@@ -201,7 +222,9 @@
/**
* Resets the full bias in nanoseconds.
+ * @hide
*/
+ @TestApi
public void resetFullBiasNanos() {
resetFlag(HAS_FULL_BIAS);
mFullBiasNanos = Long.MIN_VALUE;
@@ -226,7 +249,9 @@
/**
* Sets the sub-nanosecond bias.
+ * @hide
*/
+ @TestApi
public void setBiasNanos(double biasNanos) {
setFlag(HAS_BIAS);
mBiasNanos = biasNanos;
@@ -234,7 +259,9 @@
/**
* Resets the clock's Bias in nanoseconds.
+ * @hide
*/
+ @TestApi
public void resetBiasNanos() {
resetFlag(HAS_BIAS);
mBiasNanos = Double.NaN;
@@ -258,7 +285,9 @@
/**
* Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
+ * @hide
*/
+ @TestApi
public void setBiasUncertaintyNanos(double biasUncertaintyNanos) {
setFlag(HAS_BIAS_UNCERTAINTY);
mBiasUncertaintyNanos = biasUncertaintyNanos;
@@ -266,7 +295,9 @@
/**
* Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
+ * @hide
*/
+ @TestApi
public void resetBiasUncertaintyNanos() {
resetFlag(HAS_BIAS_UNCERTAINTY);
mBiasUncertaintyNanos = Double.NaN;
@@ -292,7 +323,9 @@
/**
* Sets the clock's Drift in nanoseconds per second.
+ * @hide
*/
+ @TestApi
public void setDriftNanosPerSecond(double driftNanosPerSecond) {
setFlag(HAS_DRIFT);
mDriftNanosPerSecond = driftNanosPerSecond;
@@ -300,7 +333,9 @@
/**
* Resets the clock's Drift in nanoseconds per second.
+ * @hide
*/
+ @TestApi
public void resetDriftNanosPerSecond() {
resetFlag(HAS_DRIFT);
mDriftNanosPerSecond = Double.NaN;
@@ -324,7 +359,9 @@
/**
* Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
+ * @hide
*/
+ @TestApi
public void setDriftUncertaintyNanosPerSecond(double driftUncertaintyNanosPerSecond) {
setFlag(HAS_DRIFT_UNCERTAINTY);
mDriftUncertaintyNanosPerSecond = driftUncertaintyNanosPerSecond;
@@ -339,14 +376,18 @@
/**
* Sets count of last hardware clock discontinuity.
+ * @hide
*/
+ @TestApi
public void setHardwareClockDiscontinuityCount(int value) {
mHardwareClockDiscontinuityCount = value;
}
/**
* Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
+ * @hide
*/
+ @TestApi
public void resetDriftUncertaintyNanosPerSecond() {
resetFlag(HAS_DRIFT_UNCERTAINTY);
mDriftUncertaintyNanosPerSecond = Double.NaN;
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 367c52f..11fecfb 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -16,6 +16,7 @@
package android.location;
+import android.annotation.TestApi;
import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
@@ -46,6 +47,7 @@
private double mCarrierPhaseUncertainty;
private int mMultipathIndicator;
private double mSnrInDb;
+ private boolean mPseudorangeRateCorrected;
// The following enumerations must be in sync with the values declared in gps.h
@@ -55,7 +57,6 @@
private static final int HAS_CARRIER_CYCLES = (1<<10);
private static final int HAS_CARRIER_PHASE = (1<<11);
private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
- private static final int HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
/** The status of multipath. */
@Retention(RetentionPolicy.SOURCE)
@@ -141,13 +142,19 @@
// End enumerations in sync with gps.h
- GnssMeasurement() {
+ /**
+ * @hide
+ */
+ @TestApi
+ public GnssMeasurement() {
initialize();
}
/**
* Sets all contents to the values stored in the provided object.
+ * @hide
*/
+ @TestApi
public void set(GnssMeasurement measurement) {
mFlags = measurement.mFlags;
mSvid = measurement.mSvid;
@@ -174,7 +181,9 @@
/**
* Resets all the contents to its original state.
+ * @hide
*/
+ @TestApi
public void reset() {
initialize();
}
@@ -189,7 +198,9 @@
/**
* Sets the Pseud-random number (PRN).
+ * @hide
*/
+ @TestApi
public void setSvid(int value) {
mSvid = value;
}
@@ -204,7 +215,9 @@
/**
* Sets the constellation type.
+ * @hide
*/
+ @TestApi
public void setConstellationType(@GnssStatus.ConstellationType int value) {
mConstellationType = value;
}
@@ -227,7 +240,9 @@
/**
* Sets the time offset at which the measurement was taken in nanoseconds.
+ * @hide
*/
+ @TestApi
public void setTimeOffsetNanos(double value) {
mTimeOffsetNanos = value;
}
@@ -244,7 +259,9 @@
/**
* Sets the sync state.
+ * @hide
*/
+ @TestApi
public void setState(int value) {
mState = value;
}
@@ -353,7 +370,9 @@
/**
* Sets the received GNSS time in nanoseconds.
+ * @hide
*/
+ @TestApi
public void setReceivedSvTimeNanos(long value) {
mReceivedSvTimeNanos = value;
}
@@ -367,7 +386,9 @@
/**
* Sets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
+ * @hide
*/
+ @TestApi
public void setReceivedSvTimeUncertaintyNanos(long value) {
mReceivedSvTimeUncertaintyNanos = value;
}
@@ -384,7 +405,9 @@
/**
* Sets the carrier-to-noise density in dB-Hz.
+ * @hide
*/
+ @TestApi
public void setCn0DbHz(double value) {
mCn0DbHz = value;
}
@@ -409,7 +432,9 @@
/**
* Sets the pseudorange rate at the timestamp in m/s.
+ * @hide
*/
+ @TestApi
public void setPseudorangeRateMetersPerSecond(double value) {
mPseudorangeRateMetersPerSecond = value;
}
@@ -421,7 +446,16 @@
* value, {@code false} if it contains an uncorrected value.
*/
public boolean isPseudorangeRateCorrected() {
- return !isFlagSet(HAS_UNCORRECTED_PSEUDORANGE_RATE);
+ return mPseudorangeRateCorrected;
+ }
+
+ /**
+ * Sets whether the pseudorange corrected.
+ * @hide
+ */
+ @TestApi
+ public void setPseudorangeRateCorrected(boolean value) {
+ mPseudorangeRateCorrected = value;
}
/**
@@ -434,7 +468,9 @@
/**
* Sets the pseudorange's rate uncertainty (1-Sigma) in m/s.
+ * @hide
*/
+ @TestApi
public void setPseudorangeRateUncertaintyMetersPerSecond(double value) {
mPseudorangeRateUncertaintyMetersPerSecond = value;
}
@@ -450,7 +486,9 @@
/**
* Sets the 'Accumulated Delta Range' state.
+ * @hide
*/
+ @TestApi
public void setAccumulatedDeltaRangeState(int value) {
mAccumulatedDeltaRangeState = value;
}
@@ -500,7 +538,9 @@
/**
* Sets the accumulated delta range in meters.
+ * @hide
*/
+ @TestApi
public void setAccumulatedDeltaRangeMeters(double value) {
mAccumulatedDeltaRangeMeters = value;
}
@@ -519,7 +559,10 @@
* Sets the accumulated delta range's uncertainty (1-sigma) in meters.
*
* The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
+ *
+ * @hide
*/
+ @TestApi
public void setAccumulatedDeltaRangeUncertaintyMeters(double value) {
mAccumulatedDeltaRangeUncertaintyMeters = value;
}
@@ -543,7 +586,9 @@
/**
* Sets the Carrier frequency (L1 or L2) in Hz.
+ * @hide
*/
+ @TestApi
public void setCarrierFrequencyHz(float carrierFrequencyHz) {
setFlag(HAS_CARRIER_FREQUENCY);
mCarrierFrequencyHz = carrierFrequencyHz;
@@ -551,7 +596,9 @@
/**
* Resets the Carrier frequency (L1 or L2) in Hz.
+ * @hide
*/
+ @TestApi
public void resetCarrierFrequencyHz() {
resetFlag(HAS_CARRIER_FREQUENCY);
mCarrierFrequencyHz = Float.NaN;
@@ -576,7 +623,9 @@
/**
* Sets the number of full carrier cycles between the satellite and the receiver.
+ * @hide
*/
+ @TestApi
public void setCarrierCycles(long value) {
setFlag(HAS_CARRIER_CYCLES);
mCarrierCycles = value;
@@ -584,7 +633,9 @@
/**
* Resets the number of full carrier cycles between the satellite and the receiver.
+ * @hide
*/
+ @TestApi
public void resetCarrierCycles() {
resetFlag(HAS_CARRIER_CYCLES);
mCarrierCycles = Long.MIN_VALUE;
@@ -613,7 +664,9 @@
/**
* Sets the RF phase detected by the receiver.
+ * @hide
*/
+ @TestApi
public void setCarrierPhase(double value) {
setFlag(HAS_CARRIER_PHASE);
mCarrierPhase = value;
@@ -621,7 +674,9 @@
/**
* Resets the RF phase detected by the receiver.
+ * @hide
*/
+ @TestApi
public void resetCarrierPhase() {
resetFlag(HAS_CARRIER_PHASE);
mCarrierPhase = Double.NaN;
@@ -646,7 +701,9 @@
/**
* Sets the Carrier-phase's uncertainty (1-Sigma) in cycles.
+ * @hide
*/
+ @TestApi
public void setCarrierPhaseUncertainty(double value) {
setFlag(HAS_CARRIER_PHASE_UNCERTAINTY);
mCarrierPhaseUncertainty = value;
@@ -654,7 +711,9 @@
/**
* Resets the Carrier-phase's uncertainty (1-Sigma) in cycles.
+ * @hide
*/
+ @TestApi
public void resetCarrierPhaseUncertainty() {
resetFlag(HAS_CARRIER_PHASE_UNCERTAINTY);
mCarrierPhaseUncertainty = Double.NaN;
@@ -670,7 +729,9 @@
/**
* Sets the 'multi-path' indicator.
+ * @hide
*/
+ @TestApi
public void setMultipathIndicator(@MultipathIndicator int value) {
mMultipathIndicator = value;
}
@@ -710,7 +771,9 @@
/**
* Sets the Signal-to-noise ratio (SNR) in dB.
+ * @hide
*/
+ @TestApi
public void setSnrInDb(double snrInDb) {
setFlag(HAS_SNR);
mSnrInDb = snrInDb;
@@ -718,7 +781,9 @@
/**
* Resets the Signal-to-noise ratio (SNR) in dB.
+ * @hide
*/
+ @TestApi
public void resetSnrInDb() {
resetFlag(HAS_SNR);
mSnrInDb = Double.NaN;
@@ -748,6 +813,7 @@
gnssMeasurement.mCarrierPhaseUncertainty = parcel.readDouble();
gnssMeasurement.mMultipathIndicator = parcel.readInt();
gnssMeasurement.mSnrInDb = parcel.readDouble();
+ gnssMeasurement.mPseudorangeRateCorrected = (parcel.readByte() != 0);
return gnssMeasurement;
}
@@ -779,6 +845,7 @@
parcel.writeDouble(mCarrierPhaseUncertainty);
parcel.writeInt(mMultipathIndicator);
parcel.writeDouble(mSnrInDb);
+ parcel.writeByte((byte) (mPseudorangeRateCorrected ? 1 : 0));
}
@Override
@@ -876,6 +943,7 @@
resetCarrierPhaseUncertainty();
setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
resetSnrInDb();
+ setPseudorangeRateCorrected(false);
}
private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java
index c0608e0..ac255c8 100644
--- a/location/java/android/location/GnssNavigationMessage.java
+++ b/location/java/android/location/GnssNavigationMessage.java
@@ -16,6 +16,7 @@
package android.location;
+import android.annotation.TestApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Parcel;
@@ -86,13 +87,19 @@
private byte[] mData;
private int mStatus;
- GnssNavigationMessage() {
+ /**
+ * @hide
+ */
+ @TestApi
+ public GnssNavigationMessage() {
initialize();
}
/**
* Sets all contents to the values stored in the provided object.
+ * @hide
*/
+ @TestApi
public void set(GnssNavigationMessage navigationMessage) {
mType = navigationMessage.mType;
mSvid = navigationMessage.mSvid;
@@ -104,7 +111,9 @@
/**
* Resets all the contents to its original state.
+ * @hide
*/
+ @TestApi
public void reset() {
initialize();
}
@@ -119,7 +128,9 @@
/**
* Sets the type of the navigation message.
+ * @hide
*/
+ @TestApi
public void setType(@GnssNavigationMessageType int value) {
mType = value;
}
@@ -165,7 +176,9 @@
/**
* Sets the Pseud-random number.
+ * @hide
*/
+ @TestApi
public void setSvid(int value) {
mSvid = value;
}
@@ -182,7 +195,9 @@
/**
* Sets the Message Identifier.
+ * @hide
*/
+ @TestApi
public void setMessageId(int value) {
mMessageId = value;
}
@@ -199,7 +214,9 @@
/**
* Sets the Sub-message identifier.
+ * @hide
*/
+ @TestApi
public void setSubmessageId(int value) {
mSubmessageId = value;
}
@@ -215,7 +232,9 @@
/**
* Sets the data associated with the Navigation Message.
+ * @hide
*/
+ @TestApi
public void setData(byte[] value) {
if (value == null) {
throw new InvalidParameterException("Data must be a non-null array");
@@ -233,7 +252,9 @@
/**
* Sets the status of the navigation message.
+ * @hide
*/
+ @TestApi
public void setStatus(int value) {
mStatus = value;
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index b8f0717..3771474 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -1738,7 +1738,10 @@
// TODO remove: implementation calls directly into implementation of native_release()
private native final void native_finalize();
- private native final void native_release();
+ /**
+ * @hide
+ */
+ public native final void native_release();
private native final int native_start(int syncEvent, int sessionId);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index c48bfc5..2aac2b3 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -2794,7 +2794,10 @@
private native final void native_finalize();
- private native final void native_release();
+ /**
+ * @hide
+ */
+ public native final void native_release();
private native final void native_start();
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 1a387be..ce12e76 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -16,14 +16,16 @@
package android.media;
+import android.annotation.NonNull;
+import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.util.Log;
-import android.util.Pair;
+import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -44,6 +46,7 @@
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import java.util.TimeZone;
import java.util.regex.Pattern;
@@ -62,89 +65,273 @@
private static final boolean DEBUG = false;
// The Exif tag names
+ /** Type is String. */
+ public static final String TAG_ARTIST = "Artist";
/** Type is int. */
- public static final String TAG_ORIENTATION = "Orientation";
+ public static final String TAG_BITS_PER_SAMPLE = "BitsPerSample";
+ /** Type is int. */
+ public static final String TAG_COMPRESSION = "Compression";
+ /** Type is String. */
+ public static final String TAG_COPYRIGHT = "Copyright";
/** Type is String. */
public static final String TAG_DATETIME = "DateTime";
/** Type is String. */
+ public static final String TAG_IMAGE_DESCRIPTION = "ImageDescription";
+ /** Type is int. */
+ public static final String TAG_IMAGE_LENGTH = "ImageLength";
+ /** Type is int. */
+ public static final String TAG_IMAGE_WIDTH = "ImageWidth";
+ /** Type is int. */
+ public static final String TAG_JPEG_INTERCHANGE_FORMAT = "JPEGInterchangeFormat";
+ /** Type is int. */
+ public static final String TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = "JPEGInterchangeFormatLength";
+ /** Type is String. */
public static final String TAG_MAKE = "Make";
/** Type is String. */
public static final String TAG_MODEL = "Model";
/** Type is int. */
- public static final String TAG_FLASH = "Flash";
+ public static final String TAG_ORIENTATION = "Orientation";
/** Type is int. */
- public static final String TAG_IMAGE_WIDTH = "ImageWidth";
+ public static final String TAG_PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
/** Type is int. */
- public static final String TAG_IMAGE_LENGTH = "ImageLength";
- /** String. Format is "num1/denom1,num2/denom2,num3/denom3". */
- public static final String TAG_GPS_LATITUDE = "GPSLatitude";
- /** String. Format is "num1/denom1,num2/denom2,num3/denom3". */
- public static final String TAG_GPS_LONGITUDE = "GPSLongitude";
+ public static final String TAG_PLANAR_CONFIGURATION = "PlanarConfiguration";
+ /** Type is rational. */
+ public static final String TAG_PRIMARY_CHROMATICITIES = "PrimaryChromaticities";
+ /** Type is rational. */
+ public static final String TAG_REFERENCE_BLACK_WHITE = "ReferenceBlackWhite";
+ /** Type is int. */
+ public static final String TAG_RESOLUTION_UNIT = "ResolutionUnit";
+ /** Type is int. */
+ public static final String TAG_ROWS_PER_STRIP = "RowsPerStrip";
+ /** Type is int. */
+ public static final String TAG_SAMPLES_PER_PIXEL = "SamplesPerPixel";
/** Type is String. */
- public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
+ public static final String TAG_SOFTWARE = "Software";
+ /** Type is int. */
+ public static final String TAG_STRIP_BYTE_COUNTS = "StripByteCounts";
+ /** Type is int. */
+ public static final String TAG_STRIP_OFFSETS = "StripOffsets";
+ /** Type is int. */
+ public static final String TAG_TRANSFER_FUNCTION = "TransferFunction";
+ /** Type is rational. */
+ public static final String TAG_WHITE_POINT = "WhitePoint";
+ /** Type is rational. */
+ public static final String TAG_X_RESOLUTION = "XResolution";
+ /** Type is rational. */
+ public static final String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
+ /** Type is int. */
+ public static final String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
+ /** Type is int. */
+ public static final String TAG_Y_CB_CR_SUB_SAMPLING = "YCbCrSubSampling";
+ /** Type is rational. */
+ public static final String TAG_Y_RESOLUTION = "YResolution";
+ /** Type is rational. */
+ public static final String TAG_APERTURE_VALUE = "ApertureValue";
+ /** Type is rational. */
+ public static final String TAG_BRIGHTNESS_VALUE = "BrightnessValue";
/** Type is String. */
- public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+ public static final String TAG_CFA_PATTERN = "CFAPattern";
+ /** Type is int. */
+ public static final String TAG_COLOR_SPACE = "ColorSpace";
/** Type is String. */
+ public static final String TAG_COMPONENTS_CONFIGURATION = "ComponentsConfiguration";
+ /** Type is rational. */
+ public static final String TAG_COMPRESSED_BITS_PER_PIXEL = "CompressedBitsPerPixel";
+ /** Type is int. */
+ public static final String TAG_CONTRAST = "Contrast";
+ /** Type is int. */
+ public static final String TAG_CUSTOM_RENDERED = "CustomRendered";
+ /** Type is String. */
+ public static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ /** Type is String. */
+ public static final String TAG_DATETIME_ORIGINAL = "DateTimeOriginal";
+ /** Type is String. */
+ public static final String TAG_DEVICE_SETTING_DESCRIPTION = "DeviceSettingDescription";
+ /** Type is double. */
+ public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
+ /** Type is String. */
+ public static final String TAG_EXIF_VERSION = "ExifVersion";
+ /** Type is double. */
+ public static final String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+ /** Type is rational. */
+ public static final String TAG_EXPOSURE_INDEX = "ExposureIndex";
+ /** Type is int. */
+ public static final String TAG_EXPOSURE_MODE = "ExposureMode";
+ /** Type is int. */
+ public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
+ /** Type is double. */
public static final String TAG_EXPOSURE_TIME = "ExposureTime";
/** Type is String. */
+ public static final String TAG_F_NUMBER = "FNumber";
+ /** Type is String. */
public static final String TAG_APERTURE = "FNumber";
/** Type is String. */
+ public static final String TAG_FILE_SOURCE = "FileSource";
+ /** Type is int. */
+ public static final String TAG_FLASH = "Flash";
+ /** Type is rational. */
+ public static final String TAG_FLASH_ENERGY = "FlashEnergy";
+ /** Type is String. */
+ public static final String TAG_FLASHPIX_VERSION = "FlashpixVersion";
+ /** Type is rational. */
+ public static final String TAG_FOCAL_LENGTH = "FocalLength";
+ /** Type is int. */
+ public static final String TAG_FOCAL_LENGTH_IN_35MM_FILM = "FocalLengthIn35mmFilm";
+ /** Type is int. */
+ public static final String TAG_FOCAL_PLANE_RESOLUTION_UNIT = "FocalPlaneResolutionUnit";
+ /** Type is rational. */
+ public static final String TAG_FOCAL_PLANE_X_RESOLUTION = "FocalPlaneXResolution";
+ /** Type is rational. */
+ public static final String TAG_FOCAL_PLANE_Y_RESOLUTION = "FocalPlaneYResolution";
+ /** Type is rational. */
+ public static final String TAG_GAIN_CONTROL = "GainControl";
+ /** Type is String. */
+ public static final String TAG_ISO_SPEED_RATINGS = "ISOSpeedRatings";
+ /** Type is String. */
public static final String TAG_ISO = "ISOSpeedRatings";
/** Type is String. */
- public static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ public static final String TAG_IMAGE_UNIQUE_ID = "ImageUniqueID";
+ /** Type is int. */
+ public static final String TAG_LIGHT_SOURCE = "LightSource";
+ /** Type is String. */
+ public static final String TAG_MAKER_NOTE = "MakerNote";
+ /** Type is rational. */
+ public static final String TAG_MAX_APERTURE_VALUE = "MaxApertureValue";
+ /** Type is int. */
+ public static final String TAG_METERING_MODE = "MeteringMode";
+ /** Type is String. */
+ public static final String TAG_OECF = "OECF";
+ /** Type is int. */
+ public static final String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
+ /** Type is int. */
+ public static final String TAG_PIXEL_Y_DIMENSION = "PixelYDimension";
+ /** Type is String. */
+ public static final String TAG_RELATED_SOUND_FILE = "RelatedSoundFile";
+ /** Type is int. */
+ public static final String TAG_SATURATION = "Saturation";
+ /** Type is int. */
+ public static final String TAG_SCENE_CAPTURE_TYPE = "SceneCaptureType";
+ /** Type is String. */
+ public static final String TAG_SCENE_TYPE = "SceneType";
+ /** Type is int. */
+ public static final String TAG_SENSING_METHOD = "SensingMethod";
+ /** Type is int. */
+ public static final String TAG_SHARPNESS = "Sharpness";
+ /** Type is rational. */
+ public static final String TAG_SHUTTER_SPEED_VALUE = "ShutterSpeedValue";
+ /** Type is String. */
+ public static final String TAG_SPATIAL_FREQUENCY_RESPONSE = "SpatialFrequencyResponse";
+ /** Type is String. */
+ public static final String TAG_SPECTRAL_SENSITIVITY = "SpectralSensitivity";
/** Type is int. */
public static final String TAG_SUBSEC_TIME = "SubSecTime";
+ /** Type is int. @hide */
+ public static final String TAG_SUBSECTIME = "SubSecTime";
+ /** Type is int. */
+ public static final String TAG_SUBSEC_TIME_DIGITIZED = "SubSecTimeDigitized";
+ /** Type is int. */
+ public static final String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
/** Type is int. */
public static final String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
/** Type is int. */
- public static final String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
-
- /**
- * @hide
- */
- public static final String TAG_SUBSECTIME = "SubSecTime";
-
+ public static final String TAG_SUBSEC_TIME_ORIGINAL = "SubSecTimeOriginal";
+ /** Type is int. */
+ public static final String TAG_SUBJECT_AREA = "SubjectArea";
+ /** Type is double. */
+ public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance";
+ /** Type is int. */
+ public static final String TAG_SUBJECT_DISTANCE_RANGE = "SubjectDistanceRange";
+ /** Type is int. */
+ public static final String TAG_SUBJECT_LOCATION = "SubjectLocation";
+ /** Type is String. */
+ public static final String TAG_USER_COMMENT = "UserComment";
+ /** Type is int. */
+ public static final String TAG_WHITE_BALANCE = "WhiteBalance";
/**
* The altitude (in meters) based on the reference in TAG_GPS_ALTITUDE_REF.
* Type is rational.
*/
public static final String TAG_GPS_ALTITUDE = "GPSAltitude";
-
/**
* 0 if the altitude is above sea level. 1 if the altitude is below sea
* level. Type is int.
*/
public static final String TAG_GPS_ALTITUDE_REF = "GPSAltitudeRef";
-
/** Type is String. */
- public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+ public static final String TAG_GPS_AREA_INFORMATION = "GPSAreaInformation";
+ /** Type is rational. */
+ public static final String TAG_GPS_DOP = "GPSDOP";
/** Type is String. */
public static final String TAG_GPS_DATESTAMP = "GPSDateStamp";
- /** Type is int. */
- public static final String TAG_WHITE_BALANCE = "WhiteBalance";
/** Type is rational. */
- public static final String TAG_FOCAL_LENGTH = "FocalLength";
+ public static final String TAG_GPS_DEST_BEARING = "GPSDestBearing";
+ /** Type is String. */
+ public static final String TAG_GPS_DEST_BEARING_REF = "GPSDestBearingRef";
+ /** Type is rational. */
+ public static final String TAG_GPS_DEST_DISTANCE = "GPSDestDistance";
+ /** Type is String. */
+ public static final String TAG_GPS_DEST_DISTANCE_REF = "GPSDestDistanceRef";
+ /** Type is rational. */
+ public static final String TAG_GPS_DEST_LATITUDE = "GPSDestLatitude";
+ /** Type is String. */
+ public static final String TAG_GPS_DEST_LATITUDE_REF = "GPSDestLatitudeRef";
+ /** Type is rational. */
+ public static final String TAG_GPS_DEST_LONGITUDE = "GPSDestLongitude";
+ /** Type is String. */
+ public static final String TAG_GPS_DEST_LONGITUDE_REF = "GPSDestLongitudeRef";
+ /** Type is int. */
+ public static final String TAG_GPS_DIFFERENTIAL = "GPSDifferential";
+ /** Type is rational. */
+ public static final String TAG_GPS_IMG_DIRECTION = "GPSImgDirection";
+ /** Type is String. */
+ public static final String TAG_GPS_IMG_DIRECTION_REF = "GPSImgDirectionRef";
+ /** String. Format is "num1/denom1,num2/denom2,num3/denom3". */
+ public static final String TAG_GPS_LATITUDE = "GPSLatitude";
+ /** Type is String. */
+ public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
+ /** String. Format is "num1/denom1,num2/denom2,num3/denom3". */
+ public static final String TAG_GPS_LONGITUDE = "GPSLongitude";
+ /** Type is String. */
+ public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
+ /** Type is String. */
+ public static final String TAG_GPS_MAP_DATUM = "GPSMapDatum";
+ /** Type is String. */
+ public static final String TAG_GPS_MEASURE_MODE = "GPSMeasureMode";
/** Type is String. Name of GPS processing method used for location finding. */
public static final String TAG_GPS_PROCESSING_METHOD = "GPSProcessingMethod";
- /** Type is double. */
- public static final String TAG_DIGITAL_ZOOM_RATIO = "DigitalZoomRatio";
- /** Type is double. */
- public static final String TAG_SUBJECT_DISTANCE = "SubjectDistance";
- /** Type is double. */
- public static final String TAG_EXPOSURE_BIAS_VALUE = "ExposureBiasValue";
+ /** Type is String. */
+ public static final String TAG_GPS_SATELLITES = "GPSSatellites";
+ /** Type is rational. */
+ public static final String TAG_GPS_SPEED = "GPSSpeed";
+ /** Type is String. */
+ public static final String TAG_GPS_SPEED_REF = "GPSSpeedRef";
+ /** Type is String. */
+ public static final String TAG_GPS_STATUS = "GPSStatus";
+ /** Type is String. */
+ public static final String TAG_GPS_TIMESTAMP = "GPSTimeStamp";
+ /** Type is rational. */
+ public static final String TAG_GPS_TRACK = "GPSTrack";
+ /** Type is String. */
+ public static final String TAG_GPS_TRACK_REF = "GPSTrackRef";
+ /** Type is String. */
+ public static final String TAG_GPS_VERSION_ID = "GPSVersionID";
+ /** Type is String. */
+ public static final String TAG_INTEROPERABILITY_INDEX = "InteroperabilityIndex";
/** Type is int. */
- public static final String TAG_LIGHT_SOURCE = "LightSource";
+ public static final String TAG_THUMBNAIL_IMAGE_LENGTH = "ThumbnailImageLength";
/** Type is int. */
- public static final String TAG_METERING_MODE = "MeteringMode";
- /** Type is int. */
- public static final String TAG_EXPOSURE_PROGRAM = "ExposureProgram";
- /** Type is int. */
- public static final String TAG_EXPOSURE_MODE = "ExposureMode";
+ public static final String TAG_THUMBNAIL_IMAGE_WIDTH = "ThumbnailImageWidth";
+
+ // Private tags used for pointing the other IFD offset. The types of the following tags are int.
+ private static final String TAG_EXIF_IFD_POINTER = "ExifIFDPointer";
+ private static final String TAG_GPS_INFO_IFD_POINTER = "GPSInfoIFDPointer";
+ private static final String TAG_INTEROPERABILITY_IFD_POINTER = "InteroperabilityIFDPointer";
// Private tags used for thumbnail information.
private static final String TAG_HAS_THUMBNAIL = "hasThumbnail";
private static final String TAG_THUMBNAIL_OFFSET = "thumbnailOffset";
private static final String TAG_THUMBNAIL_LENGTH = "thumbnailLength";
+ private static final String TAG_THUMBNAIL_DATA = "thumbnailData";
// Constants used for the Orientation Exif tag.
public static final int ORIENTATION_UNDEFINED = 0;
@@ -163,6 +350,9 @@
public static final int WHITEBALANCE_AUTO = 0;
public static final int WHITEBALANCE_MANUAL = 1;
+ private static final byte[] JPEG_SIGNATURE = new byte[] {(byte) 0xff, (byte) 0xd8, (byte) 0xff};
+ private static final int JPEG_SIGNATURE_SIZE = 3;
+
private static SimpleDateFormat sFormatter;
// See Exchangeable image file format for digital still cameras: Exif version 2.2.
@@ -208,171 +398,171 @@
// Primary image IFD TIFF tags (See JEITA CP-3451 Table 14. page 54).
private static final ExifTag[] IFD_TIFF_TAGS = new ExifTag[] {
- new ExifTag("ImageWidth", 256),
- new ExifTag("ImageLength", 257),
- new ExifTag("BitsPerSample", 258),
- new ExifTag("Compression", 259),
- new ExifTag("PhotometricInterpretation", 262),
- new ExifTag("ImageDescription", 270),
- new ExifTag("Make", 271),
- new ExifTag("Model", 272),
- new ExifTag("StripOffsets", 273),
- new ExifTag("Orientation", 274),
- new ExifTag("SamplesPerPixel", 277),
- new ExifTag("RowsPerStrip", 278),
- new ExifTag("StripByteCounts", 279),
- new ExifTag("XResolution", 282),
- new ExifTag("YResolution", 283),
- new ExifTag("PlanarConfiguration", 284),
- new ExifTag("ResolutionUnit", 296),
- new ExifTag("TransferFunction", 301),
- new ExifTag("Software", 305),
- new ExifTag("DateTime", 306),
- new ExifTag("Artist", 315),
- new ExifTag("WhitePoint", 318),
- new ExifTag("PrimaryChromaticities", 319),
- new ExifTag("JPEGInterchangeFormat", 513),
- new ExifTag("JPEGInterchangeFormatLength", 514),
- new ExifTag("YCbCrCoefficients", 529),
- new ExifTag("YCbCrSubSampling", 530),
- new ExifTag("YCbCrPositioning", 531),
- new ExifTag("ReferenceBlackWhite", 532),
- new ExifTag("Copyright", 33432),
- new ExifTag("ExifIFDPointer", 34665),
- new ExifTag("GPSInfoIFDPointer", 34853),
+ new ExifTag(TAG_IMAGE_WIDTH, 256),
+ new ExifTag(TAG_IMAGE_LENGTH, 257),
+ new ExifTag(TAG_BITS_PER_SAMPLE, 258),
+ new ExifTag(TAG_COMPRESSION, 259),
+ new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262),
+ new ExifTag(TAG_IMAGE_DESCRIPTION, 270),
+ new ExifTag(TAG_MAKE, 271),
+ new ExifTag(TAG_MODEL, 272),
+ new ExifTag(TAG_STRIP_OFFSETS, 273),
+ new ExifTag(TAG_ORIENTATION, 274),
+ new ExifTag(TAG_SAMPLES_PER_PIXEL, 277),
+ new ExifTag(TAG_ROWS_PER_STRIP, 278),
+ new ExifTag(TAG_STRIP_BYTE_COUNTS, 279),
+ new ExifTag(TAG_X_RESOLUTION, 282),
+ new ExifTag(TAG_Y_RESOLUTION, 283),
+ new ExifTag(TAG_PLANAR_CONFIGURATION, 284),
+ new ExifTag(TAG_RESOLUTION_UNIT, 296),
+ new ExifTag(TAG_TRANSFER_FUNCTION, 301),
+ new ExifTag(TAG_SOFTWARE, 305),
+ new ExifTag(TAG_DATETIME, 306),
+ new ExifTag(TAG_ARTIST, 315),
+ new ExifTag(TAG_WHITE_POINT, 318),
+ new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319),
+ new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513),
+ new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514),
+ new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529),
+ new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530),
+ new ExifTag(TAG_Y_CB_CR_POSITIONING, 531),
+ new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532),
+ new ExifTag(TAG_COPYRIGHT, 33432),
+ new ExifTag(TAG_EXIF_IFD_POINTER, 34665),
+ new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853),
};
// Primary image IFD Exif Private tags (See JEITA CP-3451 Table 15. page 55).
private static final ExifTag[] IFD_EXIF_TAGS = new ExifTag[] {
- new ExifTag("ExposureTime", 33434),
- new ExifTag("FNumber", 33437),
- new ExifTag("ExposureProgram", 34850),
- new ExifTag("SpectralSensitivity", 34852),
- new ExifTag("ISOSpeedRatings", 34855),
- new ExifTag("OECF", 34856),
- new ExifTag("ExifVersion", 36864),
- new ExifTag("DateTimeOriginal", 36867),
- new ExifTag("DateTimeDigitized", 36868),
- new ExifTag("ComponentsConfiguration", 37121),
- new ExifTag("CompressedBitsPerPixel", 37122),
- new ExifTag("ShutterSpeedValue", 37377),
- new ExifTag("ApertureValue", 37378),
- new ExifTag("BrightnessValue", 37379),
- new ExifTag("ExposureBiasValue", 37380),
- new ExifTag("MaxApertureValue", 37381),
- new ExifTag("SubjectDistance", 37382),
- new ExifTag("MeteringMode", 37383),
- new ExifTag("LightSource", 37384),
- new ExifTag("Flash", 37385),
- new ExifTag("FocalLength", 37386),
- new ExifTag("SubjectArea", 37396),
- new ExifTag("MakerNote", 37500),
- new ExifTag("UserComment", 37510),
- new ExifTag("SubSecTime", 37520),
- new ExifTag("SubSecTimeOriginal", 37521),
- new ExifTag("SubSecTimeDigitized", 37522),
- new ExifTag("FlashpixVersion", 40960),
- new ExifTag("ColorSpace", 40961),
- new ExifTag("PixelXDimension", 40962),
- new ExifTag("PixelYDimension", 40963),
- new ExifTag("RelatedSoundFile", 40964),
- new ExifTag("InteroperabilityIFDPointer", 40965),
- new ExifTag("FlashEnergy", 41483),
- new ExifTag("SpatialFrequencyResponse", 41484),
- new ExifTag("FocalPlaneXResolution", 41486),
- new ExifTag("FocalPlaneYResolution", 41487),
- new ExifTag("FocalPlaneResolutionUnit", 41488),
- new ExifTag("SubjectLocation", 41492),
- new ExifTag("ExposureIndex", 41493),
- new ExifTag("SensingMethod", 41495),
- new ExifTag("FileSource", 41728),
- new ExifTag("SceneType", 41729),
- new ExifTag("CFAPattern", 41730),
- new ExifTag("CustomRendered", 41985),
- new ExifTag("ExposureMode", 41986),
- new ExifTag("WhiteBalance", 41987),
- new ExifTag("DigitalZoomRatio", 41988),
- new ExifTag("FocalLengthIn35mmFilm", 41989),
- new ExifTag("SceneCaptureType", 41990),
- new ExifTag("GainControl", 41991),
- new ExifTag("Contrast", 41992),
- new ExifTag("Saturation", 41993),
- new ExifTag("Sharpness", 41994),
- new ExifTag("DeviceSettingDescription", 41995),
- new ExifTag("SubjectDistanceRange", 41996),
- new ExifTag("ImageUniqueID", 42016),
+ new ExifTag(TAG_EXPOSURE_TIME, 33434),
+ new ExifTag(TAG_F_NUMBER, 33437),
+ new ExifTag(TAG_EXPOSURE_PROGRAM, 34850),
+ new ExifTag(TAG_SPECTRAL_SENSITIVITY, 34852),
+ new ExifTag(TAG_ISO, 34855),
+ new ExifTag(TAG_OECF, 34856),
+ new ExifTag(TAG_EXIF_VERSION, 36864),
+ new ExifTag(TAG_DATETIME_ORIGINAL, 36867),
+ new ExifTag(TAG_DATETIME_DIGITIZED, 36868),
+ new ExifTag(TAG_COMPONENTS_CONFIGURATION, 37121),
+ new ExifTag(TAG_COMPRESSED_BITS_PER_PIXEL, 37122),
+ new ExifTag(TAG_SHUTTER_SPEED_VALUE, 37377),
+ new ExifTag(TAG_APERTURE_VALUE, 37378),
+ new ExifTag(TAG_BRIGHTNESS_VALUE, 37379),
+ new ExifTag(TAG_EXPOSURE_BIAS_VALUE, 37380),
+ new ExifTag(TAG_MAX_APERTURE_VALUE, 37381),
+ new ExifTag(TAG_SUBJECT_DISTANCE, 37382),
+ new ExifTag(TAG_METERING_MODE, 37383),
+ new ExifTag(TAG_LIGHT_SOURCE, 37384),
+ new ExifTag(TAG_FLASH, 37385),
+ new ExifTag(TAG_FOCAL_LENGTH, 37386),
+ new ExifTag(TAG_SUBJECT_AREA, 37396),
+ new ExifTag(TAG_MAKER_NOTE, 37500),
+ new ExifTag(TAG_USER_COMMENT, 37510),
+ new ExifTag(TAG_SUBSEC_TIME, 37520),
+ new ExifTag(TAG_SUBSEC_TIME_ORIG, 37521),
+ new ExifTag(TAG_SUBSEC_TIME_DIG, 37522),
+ new ExifTag(TAG_FLASHPIX_VERSION, 40960),
+ new ExifTag(TAG_COLOR_SPACE, 40961),
+ new ExifTag(TAG_PIXEL_X_DIMENSION, 40962),
+ new ExifTag(TAG_PIXEL_Y_DIMENSION, 40963),
+ new ExifTag(TAG_RELATED_SOUND_FILE, 40964),
+ new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965),
+ new ExifTag(TAG_FLASH_ENERGY, 41483),
+ new ExifTag(TAG_SPATIAL_FREQUENCY_RESPONSE, 41484),
+ new ExifTag(TAG_FOCAL_PLANE_X_RESOLUTION, 41486),
+ new ExifTag(TAG_FOCAL_PLANE_Y_RESOLUTION, 41487),
+ new ExifTag(TAG_FOCAL_PLANE_RESOLUTION_UNIT, 41488),
+ new ExifTag(TAG_SUBJECT_LOCATION, 41492),
+ new ExifTag(TAG_EXPOSURE_INDEX, 41493),
+ new ExifTag(TAG_SENSING_METHOD, 41495),
+ new ExifTag(TAG_FILE_SOURCE, 41728),
+ new ExifTag(TAG_SCENE_TYPE, 41729),
+ new ExifTag(TAG_CFA_PATTERN, 41730),
+ new ExifTag(TAG_CUSTOM_RENDERED, 41985),
+ new ExifTag(TAG_EXPOSURE_MODE, 41986),
+ new ExifTag(TAG_WHITE_BALANCE, 41987),
+ new ExifTag(TAG_DIGITAL_ZOOM_RATIO, 41988),
+ new ExifTag(TAG_FOCAL_LENGTH_IN_35MM_FILM, 41989),
+ new ExifTag(TAG_SCENE_CAPTURE_TYPE, 41990),
+ new ExifTag(TAG_GAIN_CONTROL, 41991),
+ new ExifTag(TAG_CONTRAST, 41992),
+ new ExifTag(TAG_SATURATION, 41993),
+ new ExifTag(TAG_SHARPNESS, 41994),
+ new ExifTag(TAG_DEVICE_SETTING_DESCRIPTION, 41995),
+ new ExifTag(TAG_SUBJECT_DISTANCE_RANGE, 41996),
+ new ExifTag(TAG_IMAGE_UNIQUE_ID, 42016),
};
// Primary image IFD GPS Info tags (See JEITA CP-3451 Table 16. page 56).
private static final ExifTag[] IFD_GPS_TAGS = new ExifTag[] {
- new ExifTag("GPSVersionID", 0),
- new ExifTag("GPSLatitudeRef", 1),
- new ExifTag("GPSLatitude", 2),
- new ExifTag("GPSLongitudeRef", 3),
- new ExifTag("GPSLongitude", 4),
- new ExifTag("GPSAltitudeRef", 5),
- new ExifTag("GPSAltitude", 6),
- new ExifTag("GPSTimeStamp", 7),
- new ExifTag("GPSSatellites", 8),
- new ExifTag("GPSStatus", 9),
- new ExifTag("GPSMeasureMode", 10),
- new ExifTag("GPSDOP", 11),
- new ExifTag("GPSSpeedRef", 12),
- new ExifTag("GPSSpeed", 13),
- new ExifTag("GPSTrackRef", 14),
- new ExifTag("GPSTrack", 15),
- new ExifTag("GPSImgDirectionRef", 16),
- new ExifTag("GPSImgDirection", 17),
- new ExifTag("GPSMapDatum", 18),
- new ExifTag("GPSDestLatitudeRef", 19),
- new ExifTag("GPSDestLatitude", 20),
- new ExifTag("GPSDestLongitudeRef", 21),
- new ExifTag("GPSDestLongitude", 22),
- new ExifTag("GPSDestBearingRef", 23),
- new ExifTag("GPSDestBearing", 24),
- new ExifTag("GPSDestDistanceRef", 25),
- new ExifTag("GPSDestDistance", 26),
- new ExifTag("GPSProcessingMethod", 27),
- new ExifTag("GPSAreaInformation", 28),
- new ExifTag("GPSDateStamp", 29),
- new ExifTag("GPSDifferential", 30),
+ new ExifTag(TAG_GPS_VERSION_ID, 0),
+ new ExifTag(TAG_GPS_LATITUDE_REF, 1),
+ new ExifTag(TAG_GPS_LATITUDE, 2),
+ new ExifTag(TAG_GPS_LONGITUDE_REF, 3),
+ new ExifTag(TAG_GPS_LONGITUDE, 4),
+ new ExifTag(TAG_GPS_ALTITUDE_REF, 5),
+ new ExifTag(TAG_GPS_ALTITUDE, 6),
+ new ExifTag(TAG_GPS_TIMESTAMP, 7),
+ new ExifTag(TAG_GPS_SATELLITES, 8),
+ new ExifTag(TAG_GPS_STATUS, 9),
+ new ExifTag(TAG_GPS_MEASURE_MODE, 10),
+ new ExifTag(TAG_GPS_DOP, 11),
+ new ExifTag(TAG_GPS_SPEED_REF, 12),
+ new ExifTag(TAG_GPS_SPEED, 13),
+ new ExifTag(TAG_GPS_TRACK_REF, 14),
+ new ExifTag(TAG_GPS_TRACK, 15),
+ new ExifTag(TAG_GPS_IMG_DIRECTION_REF, 16),
+ new ExifTag(TAG_GPS_IMG_DIRECTION, 17),
+ new ExifTag(TAG_GPS_MAP_DATUM, 18),
+ new ExifTag(TAG_GPS_DEST_LATITUDE_REF, 19),
+ new ExifTag(TAG_GPS_DEST_LATITUDE, 20),
+ new ExifTag(TAG_GPS_DEST_LONGITUDE_REF, 21),
+ new ExifTag(TAG_GPS_DEST_LONGITUDE, 22),
+ new ExifTag(TAG_GPS_DEST_BEARING_REF, 23),
+ new ExifTag(TAG_GPS_DEST_BEARING, 24),
+ new ExifTag(TAG_GPS_DEST_DISTANCE_REF, 25),
+ new ExifTag(TAG_GPS_DEST_DISTANCE, 26),
+ new ExifTag(TAG_GPS_PROCESSING_METHOD, 27),
+ new ExifTag(TAG_GPS_AREA_INFORMATION, 28),
+ new ExifTag(TAG_GPS_DATESTAMP, 29),
+ new ExifTag(TAG_GPS_DIFFERENTIAL, 30),
};
// Primary image IFD Interoperability tag (See JEITA CP-3451 Table 17. page 56).
private static final ExifTag[] IFD_INTEROPERABILITY_TAGS = new ExifTag[] {
- new ExifTag("InteroperabilityIndex", 1),
+ new ExifTag(TAG_INTEROPERABILITY_INDEX, 1),
};
// IFD Thumbnail tags (See JEITA CP-3451 Table 18. page 57).
private static final ExifTag[] IFD_THUMBNAIL_TAGS = new ExifTag[] {
- new ExifTag("ThumbnailImageWidth", 256),
- new ExifTag("ThumbnailImageLength", 257),
- new ExifTag("BitsPerSample", 258),
- new ExifTag("Compression", 259),
- new ExifTag("PhotometricInterpretation", 262),
- new ExifTag("ImageDescription", 270),
- new ExifTag("Make", 271),
- new ExifTag("Model", 272),
- new ExifTag("StripOffsets", 273),
- new ExifTag("Orientation", 274),
- new ExifTag("SamplesPerPixel", 277),
- new ExifTag("RowsPerStrip", 278),
- new ExifTag("StripByteCounts", 279),
- new ExifTag("XResolution", 282),
- new ExifTag("YResolution", 283),
- new ExifTag("PlanarConfiguration", 284),
- new ExifTag("ResolutionUnit", 296),
- new ExifTag("TransferFunction", 301),
- new ExifTag("Software", 305),
- new ExifTag("DateTime", 306),
- new ExifTag("Artist", 315),
- new ExifTag("WhitePoint", 318),
- new ExifTag("PrimaryChromaticities", 319),
- new ExifTag("JPEGInterchangeFormat", 513),
- new ExifTag("JPEGInterchangeFormatLength", 514),
- new ExifTag("YCbCrCoefficients", 529),
- new ExifTag("YCbCrSubSampling", 530),
- new ExifTag("YCbCrPositioning", 531),
- new ExifTag("ReferenceBlackWhite", 532),
- new ExifTag("Copyright", 33432),
- new ExifTag("ExifIFDPointer", 34665),
- new ExifTag("GPSInfoIFDPointer", 34853),
+ new ExifTag(TAG_THUMBNAIL_IMAGE_WIDTH, 256),
+ new ExifTag(TAG_THUMBNAIL_IMAGE_LENGTH, 257),
+ new ExifTag(TAG_BITS_PER_SAMPLE, 258),
+ new ExifTag(TAG_COMPRESSION, 259),
+ new ExifTag(TAG_PHOTOMETRIC_INTERPRETATION, 262),
+ new ExifTag(TAG_IMAGE_DESCRIPTION, 270),
+ new ExifTag(TAG_MAKE, 271),
+ new ExifTag(TAG_MODEL, 272),
+ new ExifTag(TAG_STRIP_OFFSETS, 273),
+ new ExifTag(TAG_ORIENTATION, 274),
+ new ExifTag(TAG_SAMPLES_PER_PIXEL, 277),
+ new ExifTag(TAG_ROWS_PER_STRIP, 278),
+ new ExifTag(TAG_STRIP_BYTE_COUNTS, 279),
+ new ExifTag(TAG_X_RESOLUTION, 282),
+ new ExifTag(TAG_Y_RESOLUTION, 283),
+ new ExifTag(TAG_PLANAR_CONFIGURATION, 284),
+ new ExifTag(TAG_RESOLUTION_UNIT, 296),
+ new ExifTag(TAG_TRANSFER_FUNCTION, 301),
+ new ExifTag(TAG_SOFTWARE, 305),
+ new ExifTag(TAG_DATETIME, 306),
+ new ExifTag(TAG_ARTIST, 315),
+ new ExifTag(TAG_WHITE_POINT, 318),
+ new ExifTag(TAG_PRIMARY_CHROMATICITIES, 319),
+ new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513),
+ new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514),
+ new ExifTag(TAG_Y_CB_CR_COEFFICIENTS, 529),
+ new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530),
+ new ExifTag(TAG_Y_CB_CR_POSITIONING, 531),
+ new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532),
+ new ExifTag(TAG_COPYRIGHT, 33432),
+ new ExifTag(TAG_EXIF_IFD_POINTER, 34665),
+ new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853),
};
// See JEITA CP-3451 Figure 5. page 9.
@@ -391,9 +581,9 @@
};
// List of tags for pointing to the other image file directory offset.
private static final ExifTag[] IFD_POINTER_TAGS = new ExifTag[] {
- new ExifTag("ExifIFDPointer", 34665),
- new ExifTag("GPSInfoPointer", 34853),
- new ExifTag("InteroperabilityIFDPointer", 40965),
+ new ExifTag(TAG_EXIF_IFD_POINTER, 34665),
+ new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853),
+ new ExifTag(TAG_INTEROPERABILITY_IFD_POINTER, 40965),
};
// List of indices of the indicated tag groups according to the IFD_POINTER_TAGS
private static final int[] IFD_POINTER_TAG_HINTS = new int[] {
@@ -401,15 +591,14 @@
};
// Tags for indicating the thumbnail offset and length
private static final ExifTag JPEG_INTERCHANGE_FORMAT_TAG =
- new ExifTag("JPEGInterchangeFormat", 513);
+ new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT, 513);
private static final ExifTag JPEG_INTERCHANGE_FORMAT_LENGTH_TAG =
- new ExifTag("JPEGInterchangeFormatLength", 514);
+ new ExifTag(TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 514);
// Mappings from tag number to tag name and each item represents one IFD tag group.
private static final HashMap[] sExifTagMapsForReading = new HashMap[EXIF_TAGS.length];
- // Mapping from tag name to tag number and the corresponding tag group.
- private static final HashMap<String, Pair<Integer, Integer>> sExifTagMapForWriting
- = new HashMap<>();
+ // Mappings from tag name to tag number and each item represents one IFD tag group.
+ private static final HashMap[] sExifTagMapsForWriting = new HashMap[EXIF_TAGS.length];
// See JPEG File Interchange Format Version 1.02.
// The following values are defined for handling JPEG streams. In this implementation, we are
@@ -443,35 +632,26 @@
static {
System.loadLibrary("media_jni");
- initRawNative();
+ nativeInitRaw();
sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
sFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
// Build up the hash tables to look up Exif tags for reading Exif tags.
for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
sExifTagMapsForReading[hint] = new HashMap();
+ sExifTagMapsForWriting[hint] = new HashMap();
for (ExifTag tag : EXIF_TAGS[hint]) {
sExifTagMapsForReading[hint].put(tag.number, tag.name);
- }
- }
-
- // Build up the hash tables to look up Exif tags for writing Exif tags.
- // There are some tags that have the same tag name in the different group. For that tags,
- // Primary image TIFF IFD and Exif private IFD have a higher priority to map than the other
- // tag groups. For the same tags, it writes one tag in the only one IFD group, which has the
- // higher priority group.
- for (int hint = EXIF_TAGS.length - 1; hint >= 0; --hint) {
- for (ExifTag tag : EXIF_TAGS[hint]) {
- sExifTagMapForWriting.put(tag.name, new Pair<>(tag.number, hint));
+ sExifTagMapsForWriting[hint].put(tag.name, tag.number);
}
}
}
private final String mFilename;
- private final FileDescriptor mFileDescriptor;
- private final InputStream mInputStream;
+ private final FileDescriptor mSeekableFileDescriptor;
+ private final AssetManager.AssetInputStream mAssetInputStream;
private boolean mIsRaw;
- private final HashMap<String, String> mAttributes = new HashMap<>();
+ private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
private boolean mHasThumbnail;
// The following values used for indicating a thumbnail position.
private int mThumbnailOffset;
@@ -488,23 +668,33 @@
if (filename == null) {
throw new IllegalArgumentException("filename cannot be null");
}
+ FileInputStream in = new FileInputStream(filename);
+ mAssetInputStream = null;
mFilename = filename;
- mFileDescriptor = null;
- mInputStream = new FileInputStream(filename);
- loadAttributes();
+ if (isSeekableFD(in.getFD())) {
+ mSeekableFileDescriptor = in.getFD();
+ } else {
+ mSeekableFileDescriptor = null;
+ }
+ loadAttributes(in);
}
/**
- * Reads Exif tags from the specified image file descriptor.
+ * Reads Exif tags from the specified image file descriptor. Attribute mutation is supported
+ * for seekable file descriptors only.
*/
public ExifInterface(FileDescriptor fileDescriptor) throws IOException {
if (fileDescriptor == null) {
throw new IllegalArgumentException("parcelFileDescriptor cannot be null");
}
+ mAssetInputStream = null;
mFilename = null;
- mFileDescriptor = fileDescriptor;
- mInputStream = new FileInputStream(fileDescriptor);
- loadAttributes();
+ if (isSeekableFD(fileDescriptor)) {
+ mSeekableFileDescriptor = fileDescriptor;
+ } else {
+ mSeekableFileDescriptor = null;
+ }
+ loadAttributes(new FileInputStream(fileDescriptor));
}
/**
@@ -516,9 +706,18 @@
throw new IllegalArgumentException("inputStream cannot be null");
}
mFilename = null;
- mFileDescriptor = null;
- mInputStream = inputStream;
- loadAttributes();
+ if (inputStream instanceof AssetManager.AssetInputStream) {
+ mAssetInputStream = (AssetManager.AssetInputStream) inputStream;
+ mSeekableFileDescriptor = null;
+ } else if (inputStream instanceof FileInputStream
+ && isSeekableFD(((FileInputStream) inputStream).getFD())) {
+ mAssetInputStream = null;
+ mSeekableFileDescriptor = ((FileInputStream) inputStream).getFD();
+ } else {
+ mAssetInputStream = null;
+ mSeekableFileDescriptor = null;
+ }
+ loadAttributes(inputStream);
}
/**
@@ -528,7 +727,15 @@
* @param tag the name of the tag.
*/
public String getAttribute(String tag) {
- return mAttributes.get(tag);
+ // Retrieves all tag groups. The value from primary image tag group has a higher priority
+ // than the value from the thumbnail tag group if there are more than one candidates.
+ for (int i = 0; i < EXIF_TAGS.length; ++i) {
+ Object value = mAttributes[i].get(tag);
+ if (value != null) {
+ return (String) value;
+ }
+ }
+ return null;
}
/**
@@ -540,11 +747,11 @@
* @param defaultValue the value to return if the tag is not available.
*/
public int getAttributeInt(String tag, int defaultValue) {
- String value = mAttributes.get(tag);
+ String value = getAttribute(tag);
if (value == null) return defaultValue;
try {
return Integer.valueOf(value);
- } catch (NumberFormatException ex) {
+ } catch (NumberFormatException e) {
return defaultValue;
}
}
@@ -558,7 +765,7 @@
* @param defaultValue the value to return if the tag is not available.
*/
public double getAttributeDouble(String tag, double defaultValue) {
- String value = mAttributes.get(tag);
+ String value = getAttribute(tag);
if (value == null) return defaultValue;
try {
int index = value.indexOf("/");
@@ -567,7 +774,7 @@
if (denom == 0) return defaultValue;
double num = Double.parseDouble(value.substring(0, index));
return num / denom;
- } catch (NumberFormatException ex) {
+ } catch (NumberFormatException e) {
return defaultValue;
}
}
@@ -579,92 +786,114 @@
* @param value the value of the tag.
*/
public void setAttribute(String tag, String value) {
- if (value == null) {
- mAttributes.remove(tag);
- return;
+ for (int i = 0 ; i < EXIF_TAGS.length; ++i) {
+ if (sExifTagMapsForWriting[i].containsKey(tag)) {
+ mAttributes[i].put(tag, value);
+ }
}
- mAttributes.put(tag, value);
}
/**
- * Initialize mAttributes with the attributes from the file mFilename.
- *
- * mAttributes is a HashMap which stores the Exif attributes of the file.
- * The key is the standard tag name and the value is the tag's value: e.g.
- * Model -> Nikon. Numeric values are stored as strings.
- *
- * This function also initialize mHasThumbnail to indicate whether the
- * file has a thumbnail inside.
+ * This function decides which parser to read the image data according to the given input stream
+ * type and the content of the input stream. In each case, it reads the first three bytes to
+ * determine whether the image data format is JPEG or not.
*/
- private void loadAttributes() throws IOException {
- FileInputStream in = null;
- try {
- if (mFilename != null) {
- in = new FileInputStream(mFilename);
- }
- if (mFileDescriptor != null) {
- in = new FileInputStream(mFileDescriptor);
- }
- if (in != null) {
- // First test whether a given file is a one of RAW format or not.
- HashMap map = getRawAttributesNative(Os.dup(in.getFD()));
- mIsRaw = map != null;
- if (mIsRaw) {
- for (Object obj : map.entrySet()) {
- Map.Entry entry = (Map.Entry) obj;
- String attrName = (String) entry.getKey();
- String attrValue = (String) entry.getValue();
-
- switch (attrName) {
- case TAG_HAS_THUMBNAIL:
- mHasThumbnail = attrValue.equalsIgnoreCase("true");
- break;
- case TAG_THUMBNAIL_OFFSET:
- mThumbnailOffset = Integer.parseInt(attrValue);
- break;
- case TAG_THUMBNAIL_LENGTH:
- mThumbnailLength = Integer.parseInt(attrValue);
- break;
- default:
- mAttributes.put(attrName, attrValue);
- break;
- }
- }
-
- if (DEBUG) {
- printAttributes();
- }
- return;
- }
- }
- } catch (ErrnoException e) {
- e.rethrowAsIOException();
- } finally {
- IoUtils.closeQuietly(in);
+ private void loadAttributes(@NonNull InputStream in) throws IOException {
+ // Initialize mAttributes.
+ for (int i = 0; i < EXIF_TAGS.length; ++i) {
+ mAttributes[i] = new HashMap();
}
- try {
- if (mFileDescriptor != null) {
- Os.lseek(mFileDescriptor, 0, OsConstants.SEEK_SET);
+ // Process RAW input stream
+ if (mAssetInputStream != null) {
+ long asset = mAssetInputStream.getNativeAsset();
+ if (handleRawResult(nativeGetRawAttributesFromAsset(asset))) {
+ return;
}
-
- getJpegAttributes(mInputStream);
- } catch (ErrnoException e) {
- e.rethrowAsIOException();
- } finally {
- IoUtils.closeQuietly(mInputStream);
+ } else if (mSeekableFileDescriptor != null) {
+ if (handleRawResult(nativeGetRawAttributesFromFileDescriptor(
+ mSeekableFileDescriptor))) {
+ return;
+ }
+ } else {
+ in = new BufferedInputStream(in, JPEG_SIGNATURE_SIZE);
+ if (!isJpegInputStream((BufferedInputStream) in) && handleRawResult(
+ nativeGetRawAttributesFromInputStream(in))) {
+ return;
+ }
}
+ // Process JPEG input stream
+ getJpegAttributes(in);
+
if (DEBUG) {
printAttributes();
}
}
+ private static boolean isJpegInputStream(BufferedInputStream in) throws IOException {
+ in.mark(JPEG_SIGNATURE_SIZE);
+ byte[] signatureBytes = new byte[JPEG_SIGNATURE_SIZE];
+ if (in.read(signatureBytes) != JPEG_SIGNATURE_SIZE) {
+ throw new EOFException();
+ }
+ boolean isJpeg = Arrays.equals(JPEG_SIGNATURE, signatureBytes);
+ in.reset();
+ return isJpeg;
+ }
+
+ private boolean handleRawResult(HashMap map) {
+ if (map == null) {
+ return false;
+ }
+
+ // Mark for disabling the save feature.
+ mIsRaw = true;
+
+ for (Map.Entry entry : (Set<Map.Entry>) map.entrySet()) {
+ String attrName = (String) entry.getKey();
+
+ switch (attrName) {
+ case TAG_HAS_THUMBNAIL:
+ mHasThumbnail = ((String) entry.getValue()).equalsIgnoreCase("true");
+ break;
+ case TAG_THUMBNAIL_OFFSET:
+ mThumbnailOffset = Integer.parseInt((String) entry.getValue());
+ break;
+ case TAG_THUMBNAIL_LENGTH:
+ mThumbnailLength = Integer.parseInt((String) entry.getValue());
+ break;
+ case TAG_THUMBNAIL_DATA:
+ mThumbnailBytes = (byte[]) entry.getValue();
+ break;
+ default:
+ setAttribute(attrName, (String) entry.getValue());
+ break;
+ }
+ }
+
+ if (DEBUG) {
+ printAttributes();
+ }
+ return true;
+ }
+
+ private static boolean isSeekableFD(FileDescriptor fd) throws IOException {
+ try {
+ Os.lseek(fd, 0, OsConstants.SEEK_CUR);
+ return true;
+ } catch (ErrnoException e) {
+ return false;
+ }
+ }
+
// Prints out attributes for debugging.
private void printAttributes() {
- Log.d(TAG, "The size of tags: " + mAttributes.size());
- for (Map.Entry<String, String> entry : mAttributes.entrySet()) {
- Log.d(TAG, "tagName: " + entry.getKey() + ", tagValue: " + entry.getValue());
+ for (int i = 0; i < mAttributes.length; ++i) {
+ Log.d(TAG, "The size of tag group[" + i + "]: " + mAttributes[i].size());
+ for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
+ Log.d(TAG, "tagName: " + entry.getKey() + ", tagValue: " + entry.getValue());
+ }
}
}
@@ -679,9 +908,9 @@
throw new UnsupportedOperationException(
"ExifInterface does not support saving attributes on RAW formats.");
}
- if (mFileDescriptor == null && mFilename == null) {
+ if (mSeekableFileDescriptor == null && mFilename == null) {
throw new UnsupportedOperationException(
- "ExifInterface does not support saving attributes for input streams.");
+ "ExifInterface does not support saving attributes for the current input.");
}
// Keep the thumbnail in memory
@@ -698,11 +927,10 @@
if (!originalFile.renameTo(tempFile)) {
throw new IOException("Could'nt rename to " + tempFile.getAbsolutePath());
}
- }
- if (mFileDescriptor != null) {
+ } else if (mSeekableFileDescriptor != null) {
tempFile = File.createTempFile("temp", "jpg");
- Os.lseek(mFileDescriptor, 0, OsConstants.SEEK_SET);
- in = new FileInputStream(mFileDescriptor);
+ Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+ in = new FileInputStream(mSeekableFileDescriptor);
out = new FileOutputStream(tempFile);
Streams.copy(in, out);
}
@@ -720,10 +948,9 @@
in = new FileInputStream(tempFile);
if (mFilename != null) {
out = new FileOutputStream(mFilename);
- }
- if (mFileDescriptor != null) {
- Os.lseek(mFileDescriptor, 0, OsConstants.SEEK_SET);
- out = new FileOutputStream(mFileDescriptor);
+ } else if (mSeekableFileDescriptor != null) {
+ Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+ out = new FileOutputStream(mSeekableFileDescriptor);
}
saveJpegAttributes(in, out);
} catch (ErrnoException e) {
@@ -760,13 +987,15 @@
// Read the thumbnail.
FileInputStream in = null;
- try {
- if (mFileDescriptor != null) {
- Os.lseek(mFileDescriptor, 0, OsConstants.SEEK_SET);
- in = new FileInputStream(mFileDescriptor);
- }
- if (mFilename != null) {
+ try {
+ if (mAssetInputStream != null) {
+ return nativeGetThumbnailFromAsset(
+ mAssetInputStream.getNativeAsset(), mThumbnailOffset, mThumbnailLength);
+ } else if (mFilename != null) {
in = new FileInputStream(mFilename);
+ } else if (mSeekableFileDescriptor != null) {
+ Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+ in = new FileInputStream(mSeekableFileDescriptor);
}
if (in == null) {
// Should not be reached this.
@@ -809,10 +1038,10 @@
* Exif tags are not available.
*/
public boolean getLatLong(float output[]) {
- String latValue = mAttributes.get(TAG_GPS_LATITUDE);
- String latRef = mAttributes.get(TAG_GPS_LATITUDE_REF);
- String lngValue = mAttributes.get(TAG_GPS_LONGITUDE);
- String lngRef = mAttributes.get(TAG_GPS_LONGITUDE_REF);
+ String latValue = getAttribute(TAG_GPS_LATITUDE);
+ String latRef = getAttribute(TAG_GPS_LATITUDE_REF);
+ String lngValue = getAttribute(TAG_GPS_LONGITUDE);
+ String lngRef = getAttribute(TAG_GPS_LONGITUDE_REF);
if (latValue != null && latRef != null && lngValue != null && lngRef != null) {
try {
@@ -850,7 +1079,7 @@
* @hide
*/
public long getDateTime() {
- String dateTimeString = mAttributes.get(TAG_DATETIME);
+ String dateTimeString = getAttribute(TAG_DATETIME);
if (dateTimeString == null
|| !sNonZeroTimePattern.matcher(dateTimeString).matches()) return -1;
@@ -862,7 +1091,7 @@
if (datetime == null) return -1;
long msecs = datetime.getTime();
- String subSecs = mAttributes.get(TAG_SUBSECTIME);
+ String subSecs = getAttribute(TAG_SUBSECTIME);
if (subSecs != null) {
try {
long sub = Long.valueOf(subSecs);
@@ -875,7 +1104,7 @@
}
}
return msecs;
- } catch (IllegalArgumentException ex) {
+ } catch (IllegalArgumentException e) {
return -1;
}
}
@@ -886,8 +1115,8 @@
* @hide
*/
public long getGpsDateTime() {
- String date = mAttributes.get(TAG_GPS_DATESTAMP);
- String time = mAttributes.get(TAG_GPS_TIMESTAMP);
+ String date = getAttribute(TAG_GPS_DATESTAMP);
+ String time = getAttribute(TAG_GPS_TIMESTAMP);
if (date == null || time == null
|| (!sNonZeroTimePattern.matcher(date).matches()
&& !sNonZeroTimePattern.matcher(time).matches())) return -1;
@@ -899,7 +1128,7 @@
Date datetime = sFormatter.parse(dateTimeString, pos);
if (datetime == null) return -1;
return datetime.getTime();
- } catch (IllegalArgumentException ex) {
+ } catch (IllegalArgumentException e) {
return -1;
}
}
@@ -1007,8 +1236,7 @@
if (dataInputStream.read(bytes) != length) {
throw new IOException("Invalid exif");
}
- mAttributes.put("UserComment",
- new String(bytes, Charset.forName("US-ASCII")));
+ setAttribute("UserComment", new String(bytes, Charset.forName("US-ASCII")));
break;
}
@@ -1026,10 +1254,9 @@
case MARKER_SOF14:
case MARKER_SOF15: {
dataInputStream.skipBytes(1);
- mAttributes.put("ImageLength",
+ setAttribute("ImageLength",
String.valueOf(dataInputStream.readUnsignedShort()));
- mAttributes.put("ImageWidth",
- String.valueOf(dataInputStream.readUnsignedShort()));
+ setAttribute("ImageWidth", String.valueOf(dataInputStream.readUnsignedShort()));
length -= 5;
break;
}
@@ -1166,38 +1393,44 @@
readImageFileDirectory(dataInputStream, IFD_TIFF_HINT);
// Process thumbnail.
- try {
- int jpegInterchangeFormat = Integer.parseInt(
- mAttributes.get(JPEG_INTERCHANGE_FORMAT_TAG.name));
- int jpegInterchangeFormatLength = Integer.parseInt(
- mAttributes.get(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name));
- // The following code limits the size of thumbnail size not to overflow EXIF data area.
- jpegInterchangeFormatLength = Math.min(jpegInterchangeFormat
- + jpegInterchangeFormatLength, exifOffsetFromBeginning + exifBytes.length)
- - jpegInterchangeFormat;
- if (jpegInterchangeFormat > 0 && jpegInterchangeFormatLength > 0) {
- mHasThumbnail = true;
- mThumbnailOffset = exifOffsetFromBeginning + jpegInterchangeFormat;
- mThumbnailLength = jpegInterchangeFormatLength;
+ String jpegInterchangeFormatString = getAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name);
+ String jpegInterchangeFormatLengthString =
+ getAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name);
+ if (jpegInterchangeFormatString != null && jpegInterchangeFormatLengthString != null) {
+ try {
+ int jpegInterchangeFormat = Integer.parseInt(jpegInterchangeFormatString);
+ int jpegInterchangeFormatLength = Integer
+ .parseInt(jpegInterchangeFormatLengthString);
+ // The following code limits the size of thumbnail size not to overflow EXIF data area.
+ jpegInterchangeFormatLength = Math.min(jpegInterchangeFormat
+ + jpegInterchangeFormatLength, exifOffsetFromBeginning + exifBytes.length)
+ - jpegInterchangeFormat;
+ if (jpegInterchangeFormat > 0 && jpegInterchangeFormatLength > 0) {
+ mHasThumbnail = true;
+ mThumbnailOffset = exifOffsetFromBeginning + jpegInterchangeFormat;
+ mThumbnailLength = jpegInterchangeFormatLength;
- // Do not store a thumbnail in memory if the given input can be re-read.
- if (mFileDescriptor == null && mFilename == null) {
- byte[] thumbnailBytes = new byte[jpegInterchangeFormatLength];
- dataInputStream.seek(jpegInterchangeFormat);
- dataInputStream.readFully(thumbnailBytes);
- mThumbnailBytes = thumbnailBytes;
+ if (mFilename == null && mAssetInputStream == null
+ && mSeekableFileDescriptor == null) {
+ // Save the thumbnail in memory if the input doesn't support reading again.
+ byte[] thumbnailBytes = new byte[jpegInterchangeFormatLength];
+ dataInputStream.seek(jpegInterchangeFormat);
+ dataInputStream.readFully(thumbnailBytes);
+ mThumbnailBytes = thumbnailBytes;
- if (DEBUG) {
- Bitmap bitmap = BitmapFactory.decodeByteArray(
- thumbnailBytes, 0, thumbnailBytes.length);
- Log.d(TAG, "Thumbnail offset: " + mThumbnailOffset + ", length: "
- + mThumbnailLength + ", width: " + bitmap.getWidth() + ", height: "
- + bitmap.getHeight());
+ if (DEBUG) {
+ Bitmap bitmap = BitmapFactory.decodeByteArray(
+ thumbnailBytes, 0, thumbnailBytes.length);
+ Log.d(TAG, "Thumbnail offset: " + mThumbnailOffset + ", length: "
+ + mThumbnailLength + ", width: " + bitmap.getWidth()
+ + ", height: "
+ + bitmap.getHeight());
+ }
}
}
+ } catch (NumberFormatException e) {
+ // Ignored the corrupted image.
}
- } catch (NumberFormatException e) {
- // Ignored the corrupted image.
}
// For compatibility, keep data formats as follows.
@@ -1208,7 +1441,7 @@
convertToRational(TAG_FOCAL_LENGTH);
convertToDouble(TAG_DIGITAL_ZOOM_RATIO);
convertToDouble(TAG_EXPOSURE_TIME);
- convertToDouble(TAG_APERTURE);
+ convertToDouble(TAG_F_NUMBER);
convertToDouble(TAG_SUBJECT_DISTANCE);
convertToInt(TAG_ISO);
convertToDouble(TAG_EXPOSURE_BIAS_VALUE);
@@ -1224,29 +1457,29 @@
convertToTimetamp(TAG_GPS_TIMESTAMP);
// The value of DATETIME tag has the same value of DATETIME_ORIGINAL tag.
- String valueOfDateTimeOriginal = mAttributes.get("DateTimeOriginal");
+ String valueOfDateTimeOriginal = getAttribute("DateTimeOriginal");
if (valueOfDateTimeOriginal != null) {
- mAttributes.put(TAG_DATETIME, valueOfDateTimeOriginal);
+ setAttribute(TAG_DATETIME, valueOfDateTimeOriginal);
}
// Add the default value.
- if (!mAttributes.containsKey(TAG_IMAGE_WIDTH)) {
- mAttributes.put(TAG_IMAGE_WIDTH, "0");
+ if (getAttribute(TAG_IMAGE_WIDTH) == null) {
+ setAttribute(TAG_IMAGE_WIDTH, "0");
}
- if (!mAttributes.containsKey(TAG_IMAGE_LENGTH)) {
- mAttributes.put(TAG_IMAGE_LENGTH, "0");
+ if (getAttribute(TAG_IMAGE_LENGTH) == null) {
+ setAttribute(TAG_IMAGE_LENGTH, "0");
}
- if (!mAttributes.containsKey(TAG_ORIENTATION)) {
- mAttributes.put(TAG_ORIENTATION, "0");
+ if (getAttribute(TAG_ORIENTATION) == null) {
+ setAttribute(TAG_ORIENTATION, "0");
}
- if (!mAttributes.containsKey(TAG_LIGHT_SOURCE)) {
- mAttributes.put(TAG_LIGHT_SOURCE, "0");
+ if (getAttribute(TAG_LIGHT_SOURCE) == null) {
+ setAttribute(TAG_LIGHT_SOURCE, "0");
}
}
// Converts the tag value to timestamp; Otherwise deletes the given tag.
private void convertToTimetamp(String tagName) {
- String entryValue = mAttributes.get(tagName);
+ String entryValue = getAttribute(tagName);
if (entryValue == null) return;
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
String[] components = entryValue.split(",");
@@ -1266,16 +1499,16 @@
int value = numerator / denominator;
stringBuilder.append(String.format("%02d", value));
}
- mAttributes.put(tagName, stringBuilder.toString());
+ setAttribute(tagName, stringBuilder.toString());
} else if (dataFormat != IFD_FORMAT_STRING) {
- mAttributes.remove(tagName);
+ setAttribute(tagName, null);
}
}
// Checks the tag value of a given tag formatted in double type; Otherwise try to convert it to
// double type or delete it.
private void convertToDouble(String tagName) {
- String entryValue = mAttributes.get(tagName);
+ String entryValue = getAttribute(tagName);
if (entryValue == null) return;
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
switch (dataFormat) {
@@ -1295,21 +1528,21 @@
}
stringBuilder.append((double) numerator / denominator);
}
- mAttributes.put(tagName, stringBuilder.toString());
+ setAttribute(tagName, stringBuilder.toString());
break;
}
case IFD_FORMAT_DOUBLE:
// Keep it as is.
break;
default:
- mAttributes.remove(tagName);
+ setAttribute(tagName, null);
break;
}
}
// Checks the tag value of a given tag formatted in int type; Otherwise deletes the tag value.
private void convertToRational(String tagName) {
- String entryValue = mAttributes.get(tagName);
+ String entryValue = getAttribute(tagName);
if (entryValue == null) return;
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
switch (dataFormat) {
@@ -1324,25 +1557,25 @@
double doubleValue = Double.parseDouble(component);
stringBuilder.append((int) (doubleValue * 10000.0)).append("/").append(10000);
}
- mAttributes.put(tagName, stringBuilder.toString());
+ setAttribute(tagName, stringBuilder.toString());
break;
}
case IFD_FORMAT_SRATIONAL:
// Keep it as is.
break;
default:
- mAttributes.remove(tagName);
+ setAttribute(tagName, null);
break;
}
}
// Checks the tag value of a given tag formatted in int type; Otherwise deletes the tag value.
private void convertToInt(String tagName) {
- String entryValue = mAttributes.get(tagName);
+ String entryValue = getAttribute(tagName);
if (entryValue == null) return;
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
if (dataFormat != IFD_FORMAT_SLONG) {
- mAttributes.remove(tagName);
+ setAttribute(tagName, null);
}
}
@@ -1431,7 +1664,7 @@
String entryValue = readExifEntryValue(
dataInputStream, dataFormat, numberOfComponents);
if (entryValue != null) {
- mAttributes.put(tagName, entryValue);
+ setAttribute(tagName, entryValue);
}
} else {
StringBuilder entryValueBuilder = new StringBuilder();
@@ -1442,7 +1675,7 @@
entryValueBuilder.append(readExifEntryValue(
dataInputStream, dataFormat, numberOfComponents));
}
- mAttributes.put(tagName, entryValueBuilder.toString());
+ setAttribute(tagName, entryValueBuilder.toString());
}
if (dataInputStream.peek() != nextEntryOffset) {
@@ -1517,8 +1750,6 @@
StringBuilder stringBuilder = new StringBuilder();
while (true) {
int ch = bytes[index];
- if (ch < 0)
- throw new EOFException();
if (ch == 0)
break;
if (ch >= 32)
@@ -1554,49 +1785,46 @@
int[] ifdOffsets = new int[EXIF_TAGS.length];
int[] ifdDataSizes = new int[EXIF_TAGS.length];
- // Maps to store tags per IFD tag group
- HashMap[] ifdTags = new HashMap[EXIF_TAGS.length];
- for (int i = 0; i < EXIF_TAGS.length; ++i) {
- ifdTags[i] = new HashMap();
- }
-
// Remove IFD pointer tags (we'll re-add it later.)
for (ExifTag tag : IFD_POINTER_TAGS) {
- mAttributes.remove(tag.name);
- }
-
- // Assign tags to the corresponding group
- for (Map.Entry<String, String> entry : mAttributes.entrySet()) {
- Pair<Integer, Integer> pair = sExifTagMapForWriting.get(entry.getKey());
- if (pair != null) {
- int tagNumber = pair.first;
- int hint = pair.second;
- ifdTags[hint].put(tagNumber, entry.getValue());
- }
+ setAttribute(tag.name, null);
}
// Add IFD pointer tags. The next offset of primary image TIFF IFD will have thumbnail IFD
// offset when there is one or more tags in the thumbnail IFD.
- if (!ifdTags[IFD_INTEROPERABILITY_HINT].isEmpty()) {
- ifdTags[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].number, "0");
+ if (!mAttributes[IFD_INTEROPERABILITY_HINT].isEmpty()) {
+ mAttributes[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].name, "0");
}
- if (!ifdTags[IFD_EXIF_HINT].isEmpty()) {
- ifdTags[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].number, "0");
+ if (!mAttributes[IFD_EXIF_HINT].isEmpty()) {
+ mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].name, "0");
}
- if (!ifdTags[IFD_GPS_HINT].isEmpty()) {
- ifdTags[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].number, "0");
+ if (!mAttributes[IFD_GPS_HINT].isEmpty()) {
+ mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].name, "0");
}
+ // Remove old thumbnail data
+ setAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name, null);
+ setAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, null);
if (mHasThumbnail) {
- ifdTags[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.number, "0");
- ifdTags[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.number,
+ mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name, "0");
+ mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name,
String.valueOf(mThumbnailLength));
}
+ // Remove null value tags.
+ for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
+ for (Object obj : mAttributes[hint].entrySet().toArray()) {
+ Map.Entry entry = (Map.Entry) obj;
+ if (entry.getValue() == null) {
+ mAttributes[hint].remove(entry.getKey());
+ }
+ }
+ }
+
// Calculate IFD group data area sizes. IFD group data area is assigned to save the entry
// value which has a bigger size than 4 bytes.
for (int i = 0; i < 5; ++i) {
int sum = 0;
- for (Object entry : ifdTags[i].entrySet()) {
+ for (Map.Entry entry : (Set<Map.Entry>) mAttributes[i].entrySet()) {
String entryValue = (String) ((Map.Entry) entry).getValue();
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
int size = getSizeOfExifEntryValue(dataFormat, entryValue);
@@ -1610,16 +1838,16 @@
// Calculate IFD offsets.
int position = 8;
for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
- if (!ifdTags[hint].isEmpty()) {
+ if (!mAttributes[hint].isEmpty()) {
ifdOffsets[hint] = position;
- position += 2 + ifdTags[hint].size() * 12 + 4 + ifdDataSizes[hint];
+ position += 2 + mAttributes[hint].size() * 12 + 4 + ifdDataSizes[hint];
}
}
if (mHasThumbnail) {
int thumbnailOffset = position;
- ifdTags[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.number,
+ mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
String.valueOf(thumbnailOffset));
- ifdTags[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.number,
+ mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name,
String.valueOf(mThumbnailLength));
mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
position += mThumbnailLength;
@@ -1631,21 +1859,21 @@
Log.d(TAG, "totalSize length: " + totalSize);
for (int i = 0; i < 5; ++i) {
Log.d(TAG, String.format("index: %d, offsets: %d, tag count: %d, data sizes: %d",
- i, ifdOffsets[i], ifdTags[i].size(), ifdDataSizes[i]));
+ i, ifdOffsets[i], mAttributes[i].size(), ifdDataSizes[i]));
}
}
// Update IFD pointer tags with the calculated offsets.
- if (!ifdTags[IFD_EXIF_HINT].isEmpty()) {
- ifdTags[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].number,
+ if (!mAttributes[IFD_EXIF_HINT].isEmpty()) {
+ mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[0].name,
String.valueOf(ifdOffsets[IFD_EXIF_HINT]));
}
- if (!ifdTags[IFD_GPS_HINT].isEmpty()) {
- ifdTags[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].number,
+ if (!mAttributes[IFD_GPS_HINT].isEmpty()) {
+ mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].name,
String.valueOf(ifdOffsets[IFD_GPS_HINT]));
}
- if (!ifdTags[IFD_INTEROPERABILITY_HINT].isEmpty()) {
- ifdTags[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].number,
+ if (!mAttributes[IFD_INTEROPERABILITY_HINT].isEmpty()) {
+ mAttributes[IFD_EXIF_HINT].put(IFD_POINTER_TAGS[2].name,
String.valueOf(ifdOffsets[IFD_INTEROPERABILITY_HINT]));
}
@@ -1658,16 +1886,16 @@
// Write IFD groups. See JEITA CP-3451C Figure 7. page 12.
for (int hint = 0; hint < EXIF_TAGS.length; ++hint) {
- if (!ifdTags[hint].isEmpty()) {
+ if (!mAttributes[hint].isEmpty()) {
// See JEITA CP-3451C 4.6.2 IFD structure. page 13.
// Write entry count
- dataOutputStream.writeUnsignedShort(ifdTags[hint].size());
+ dataOutputStream.writeUnsignedShort(mAttributes[hint].size());
// Write entry info
- int dataOffset = ifdOffsets[hint] + 2 + ifdTags[hint].size() * 12 + 4;
- for (Object obj : ifdTags[hint].entrySet()) {
- Map.Entry entry = (Map.Entry) obj;
- int tagNumber = (int) entry.getKey();
+ int dataOffset = ifdOffsets[hint] + 2 + mAttributes[hint].size() * 12 + 4;
+ for (Map.Entry entry : (Set<Map.Entry>) mAttributes[hint].entrySet()) {
+ // Convert tag name to tag number.
+ int tagNumber = (int) sExifTagMapsForWriting[hint].get(entry.getKey());
String entryValue = (String) entry.getValue();
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
@@ -1695,15 +1923,14 @@
// Write the next offset. It writes the offset of thumbnail IFD if there is one or
// more tags in the thumbnail IFD when the current IFD is the primary image TIFF
// IFD; Otherwise 0.
- if (hint == 0 && !ifdTags[IFD_THUMBNAIL_HINT].isEmpty()) {
+ if (hint == 0 && !mAttributes[IFD_THUMBNAIL_HINT].isEmpty()) {
dataOutputStream.writeUnsignedInt(ifdOffsets[IFD_THUMBNAIL_HINT]);
} else {
dataOutputStream.writeUnsignedInt(0);
}
// Write values of data field exceeding 4 bytes after the next offset.
- for (Object obj : ifdTags[hint].entrySet()) {
- Map.Entry entry = (Map.Entry) obj;
+ for (Map.Entry entry : (Set<Map.Entry>) mAttributes[hint].entrySet()) {
String entryValue = (String) entry.getValue();
int dataFormat = getDataFormatOfExifEntryValue(entryValue);
@@ -1988,6 +2215,10 @@
}
// JNI methods for RAW formats.
- private static native void initRawNative();
- private static native HashMap getRawAttributesNative(FileDescriptor fileDescriptor);
+ private static native void nativeInitRaw();
+ private static native byte[] nativeGetThumbnailFromAsset(
+ long asset, int thumbnailOffset, int thumbnailLength);
+ private static native HashMap nativeGetRawAttributesFromAsset(long asset);
+ private static native HashMap nativeGetRawAttributesFromFileDescriptor(FileDescriptor fd);
+ private static native HashMap nativeGetRawAttributesFromInputStream(InputStream in);
}
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index c08f4bf..81cc035 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -335,7 +335,6 @@
switch (status) {
case ACQUIRE_SUCCESS:
- si.createSurfacePlanes();
si.mIsImageValid = true;
case ACQUIRE_NO_BUFS:
case ACQUIRE_MAX_IMAGES:
@@ -693,7 +692,7 @@
width = ImageReader.this.getWidth();
break;
default:
- width = nativeGetWidth(mFormat);
+ width = nativeGetWidth();
}
return width;
}
@@ -709,7 +708,7 @@
height = ImageReader.this.getHeight();
break;
default:
- height = nativeGetHeight(mFormat);
+ height = nativeGetHeight();
}
return height;
}
@@ -729,6 +728,10 @@
@Override
public Plane[] getPlanes() {
throwISEIfImageIsInvalid();
+
+ if (mPlanes == null) {
+ mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
+ }
// Shallow copy is fine.
return mPlanes.clone();
}
@@ -766,7 +769,8 @@
}
private void clearSurfacePlanes() {
- if (mIsImageValid) {
+ // Image#getPlanes may not be called before the image is closed.
+ if (mIsImageValid && mPlanes != null) {
for (int i = 0; i < mPlanes.length; i++) {
if (mPlanes[i] != null) {
mPlanes[i].clearBuffer();
@@ -776,32 +780,25 @@
}
}
- private void createSurfacePlanes() {
- mPlanes = new SurfacePlane[ImageReader.this.mNumPlanes];
- for (int i = 0; i < ImageReader.this.mNumPlanes; i++) {
- mPlanes[i] = nativeCreatePlane(i, ImageReader.this.mFormat);
- }
- }
private class SurfacePlane extends android.media.Image.Plane {
- // SurfacePlane instance is created by native code when a new SurfaceImage is created
- private SurfacePlane(int index, int rowStride, int pixelStride) {
- mIndex = index;
+ // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
+ // called
+ private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
mRowStride = rowStride;
mPixelStride = pixelStride;
+ mBuffer = buffer;
+ /**
+ * Set the byteBuffer order according to host endianness (native
+ * order), otherwise, the byteBuffer order defaults to
+ * ByteOrder.BIG_ENDIAN.
+ */
+ mBuffer.order(ByteOrder.nativeOrder());
}
@Override
public ByteBuffer getBuffer() {
- SurfaceImage.this.throwISEIfImageIsInvalid();
- if (mBuffer != null) {
- return mBuffer;
- } else {
- mBuffer = SurfaceImage.this.nativeImageGetBuffer(mIndex,
- ImageReader.this.mFormat);
- // Set the byteBuffer order according to host endianness (native order),
- // otherwise, the byteBuffer order defaults to ByteOrder.BIG_ENDIAN.
- return mBuffer.order(ByteOrder.nativeOrder());
- }
+ throwISEIfImageIsInvalid();
+ return mBuffer;
}
@Override
@@ -837,7 +834,6 @@
mBuffer = null;
}
- final private int mIndex;
final private int mPixelStride;
final private int mRowStride;
@@ -860,10 +856,10 @@
// If this image is detached from the ImageReader.
private AtomicBoolean mIsDetached = new AtomicBoolean(false);
- private synchronized native ByteBuffer nativeImageGetBuffer(int idx, int readerFormat);
- private synchronized native SurfacePlane nativeCreatePlane(int idx, int readerFormat);
- private synchronized native int nativeGetWidth(int format);
- private synchronized native int nativeGetHeight(int format);
+ private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
+ int readerFormat);
+ private synchronized native int nativeGetWidth();
+ private synchronized native int nativeGetHeight();
private synchronized native int nativeGetFormat(int readerFormat);
}
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 851d436..83a4f17 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -748,8 +748,8 @@
final private int mPixelStride;
final private int mRowStride;
- // SurfacePlane instance is created by native code when a new
- // SurfaceImage is created
+ // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
+ // called
private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
mRowStride = rowStride;
mPixelStride = pixelStride;
@@ -795,7 +795,7 @@
}
- // this will create the SurfacePlane object and fill the information
+ // Create the SurfacePlane object and fill the information
private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt);
private synchronized native int nativeGetWidth();
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 4977391..86ebae1 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -16,10 +16,6 @@
package android.media;
-import com.android.internal.database.SortCursor;
-
-import libcore.io.Streams;
-
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
@@ -32,12 +28,15 @@
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.RemoteException;
import android.provider.MediaStore;
import android.provider.Settings;
import android.provider.Settings.System;
import android.util.Log;
+import com.android.internal.database.SortCursor;
+
+import libcore.io.Streams;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -644,7 +643,8 @@
public static Uri getActualDefaultRingtoneUri(Context context, int type) {
String setting = getSettingForType(type);
if (setting == null) return null;
- final String uriString = Settings.System.getString(context.getContentResolver(), setting);
+ final String uriString = Settings.System.getStringForUser(context.getContentResolver(),
+ setting, context.getUserId());
return uriString != null ? Uri.parse(uriString) : null;
}
@@ -663,8 +663,8 @@
String setting = getSettingForType(type);
if (setting == null) return;
- Settings.System.putString(resolver, setting,
- ringtoneUri != null ? ringtoneUri.toString() : null);
+ Settings.System.putStringForUser(resolver, setting,
+ ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId());
// Stream selected ringtone into cache so it's available for playback
// when CE storage is still locked
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 3642155..fe2796c 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -365,7 +365,7 @@
if (options == null) {
throw new IllegalArgumentException("options are null");
}
- subscribeInternal(parentId, options, callback);
+ subscribeInternal(parentId, new Bundle(options), callback);
}
/**
@@ -1116,7 +1116,7 @@
}
}
mCallbacks.add(callback);
- mOptionsList.add(options == null ? null : new Bundle(options));
+ mOptionsList.add(options);
}
public boolean removeCallback(Bundle options) {
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index a332195..e8c50e3 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -575,16 +575,11 @@
/**
* The original network ID of this TV channel.
*
- * <p>This is used to identify the originating delivery system, if applicable. Use the same
- * coding for {@code original_network_id} in the underlying broadcast standard if it is
- * defined there (e.g. ETSI EN 300 468/TR 101 211 and ARIB STD-B10). If channels cannot be
- * globally identified by 2-tuple {{@link #COLUMN_TRANSPORT_STREAM_ID},
- * {@link #COLUMN_SERVICE_ID}}, one must carefully assign a value to this field to form a
- * unique 3-tuple identification {{@code COLUMN_ORIGINAL_NETWORK_ID},
- * {@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}} for its channels.
+ * <p>It is used to identify the originating delivery system, if applicable. Use the same
+ * coding for {@code original_network_id} for ETSI EN 300 468/TR 101 211 and ARIB STD-B10.
*
- * <p>This is a required field if the channel cannot be uniquely identified by a 2-tuple
- * {{@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}}.
+ * <p>This is a required field only if the underlying broadcast standard defines the same
+ * name field. Otherwise, leave empty.
*
* <p>Type: INTEGER
*/
@@ -593,13 +588,13 @@
/**
* The transport stream ID of this channel.
*
- * <p>This is used to identify the Transport Stream that contains the current channel from
- * any other multiplex within a network, if applicable. Use the same coding for
+ * <p>It is used to identify the Transport Stream that contains the current channel from any
+ * other multiplex within a network, if applicable. Use the same coding for
* {@code transport_stream_id} defined in ISO/IEC 13818-1 if the channel is transmitted via
- * the MPEG Transport Stream as is the case for many digital broadcast standards.
+ * the MPEG Transport Stream.
*
- * <p>This is a required field if the current channel is transmitted via the MPEG Transport
- * Stream.
+ * <p>This is a required field only if the current channel is transmitted via the MPEG
+ * Transport Stream. Leave empty otherwise.
*
* <p>Type: INTEGER
*/
@@ -608,15 +603,13 @@
/**
* The service ID of this channel.
*
- * <p>This is used to identify the current service (roughly equivalent to channel) from any
- * other service within the Transport Stream, if applicable. Use the same coding for
- * {@code service_id} in the underlying broadcast standard if it is defined there (e.g. ETSI
- * EN 300 468 and ARIB STD-B10) or {@code program_number} (which usually has the same value
- * as {@code service_id}) in ISO/IEC 13818-1 if the channel is transmitted via the MPEG
- * Transport Stream.
+ * <p>It is used to identify the current service, or channel from any other services within
+ * a given Transport Stream, if applicable. Use the same coding for {@code service_id} in
+ * ETSI EN 300 468 and ARIB STD-B10 or {@code program_number} in ISO/IEC 13818-1.
*
- * <p>This is a required field if the current channel is transmitted via the MPEG Transport
- * Stream.
+ * <p>This is a required field only if the underlying broadcast standard defines the same
+ * name field, or the current channel is transmitted via the MPEG Transport Stream. Leave
+ * empty otherwise.
*
* <p>Type: INTEGER
*/
diff --git a/media/jni/android_media_ExifInterface.cpp b/media/jni/android_media_ExifInterface.cpp
index f7481af..418a3f2 100644
--- a/media/jni/android_media_ExifInterface.cpp
+++ b/media/jni/android_media_ExifInterface.cpp
@@ -19,12 +19,15 @@
#include "android_media_Utils.h"
+#include "android/graphics/CreateJavaOutputStreamAdaptor.h"
#include "src/piex_types.h"
#include "src/piex.h"
#include <jni.h>
#include <JNIHelp.h>
+#include <androidfw/Asset.h>
#include <android_runtime/AndroidRuntime.h>
+#include <android/graphics/Utils.h>
#include <nativehelper/ScopedLocalRef.h>
#include <utils/Log.h>
@@ -35,6 +38,9 @@
using namespace android;
+static const char kJpegSignatureChars[] = {(char)0xff, (char)0xd8, (char)0xff};
+static const int kJpegSignatureSize = 3;
+
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className);
@@ -82,18 +88,48 @@
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
}
-static jobject ExifInterface_getRawMetadata(
- JNIEnv* env, jclass /* clazz */, jobject jfileDescriptor) {
- int fd = jniGetFDFromFileDescriptor(env, jfileDescriptor);
- if (fd < 0) {
- ALOGI("Invalid file descriptor");
+static bool is_asset_stream(const SkStream& stream) {
+ return stream.hasLength() && stream.hasPosition();
+}
+
+static jobject ExifInterface_getThumbnailFromAsset(
+ JNIEnv* env, jclass /* clazz */, jlong jasset, jint jthumbnailOffset,
+ jint jthumbnailLength) {
+ Asset* asset = reinterpret_cast<Asset*>(jasset);
+ std::unique_ptr<AssetStreamAdaptor> stream(new AssetStreamAdaptor(asset));
+
+ std::unique_ptr<jbyte[]> thumbnailData(new jbyte[(int)jthumbnailLength]);
+ if (thumbnailData.get() == NULL) {
+ ALOGI("No memory to get thumbnail");
return NULL;
}
- piex::PreviewImageData image_data;
- std::unique_ptr<FileStream> stream(new FileStream(fd));
+ // Do not know the current offset. So rewind it.
+ stream->rewind();
- if (!GetExifFromRawImage(stream.get(), String8("[file descriptor]"), image_data)) {
+ // Read thumbnail.
+ stream->skip((int)jthumbnailOffset);
+ stream->read((void*)thumbnailData.get(), (int)jthumbnailLength);
+
+ // Copy to the byte array.
+ jbyteArray byteArray = env->NewByteArray(jthumbnailLength);
+ env->SetByteArrayRegion(byteArray, 0, jthumbnailLength, thumbnailData.get());
+ return byteArray;
+}
+
+static jobject getRawAttributes(JNIEnv* env, SkStream* stream, bool returnThumbnail) {
+ std::unique_ptr<SkStream> streamDeleter(stream);
+
+ std::unique_ptr<::piex::StreamInterface> piexStream;
+ if (is_asset_stream(*stream)) {
+ piexStream.reset(new AssetStream(streamDeleter.release()));
+ } else {
+ piexStream.reset(new BufferedStream(streamDeleter.release()));
+ }
+
+ piex::PreviewImageData image_data;
+
+ if (!GetExifFromRawImage(piexStream.get(), String8("[piex stream]"), image_data)) {
ALOGI("Raw image not detected");
return NULL;
}
@@ -253,7 +289,117 @@
}
}
- return KeyedVectorToHashMap(env, map);
+ jobject hashMap = KeyedVectorToHashMap(env, map);
+
+ if (returnThumbnail) {
+ std::unique_ptr<jbyte[]> thumbnailData(new jbyte[image_data.thumbnail.length]);
+ if (thumbnailData.get() == NULL) {
+ ALOGE("No memory to parse a thumbnail");
+ return NULL;
+ }
+ jbyteArray jthumbnailByteArray = env->NewByteArray(image_data.thumbnail.length);
+ if (jthumbnailByteArray == NULL) {
+ ALOGE("No memory to parse a thumbnail");
+ return NULL;
+ }
+ piexStream.get()->GetData(image_data.thumbnail.offset, image_data.thumbnail.length,
+ (uint8_t*)thumbnailData.get());
+ env->SetByteArrayRegion(
+ jthumbnailByteArray, 0, image_data.thumbnail.length, thumbnailData.get());
+ jstring jkey = env->NewStringUTF(String8("thumbnailData"));
+ env->CallObjectMethod(hashMap, gFields.hashMap.put, jkey, jthumbnailByteArray);
+ env->DeleteLocalRef(jkey);
+ env->DeleteLocalRef(jthumbnailByteArray);
+ }
+ return hashMap;
+}
+
+static jobject ExifInterface_getRawAttributesFromAsset(
+ JNIEnv* env, jclass /* clazz */, jlong jasset) {
+ std::unique_ptr<char[]> jpegSignature(new char[kJpegSignatureSize]);
+ if (jpegSignature.get() == NULL) {
+ ALOGE("No enough memory to parse");
+ return NULL;
+ }
+
+ Asset* asset = reinterpret_cast<Asset*>(jasset);
+ std::unique_ptr<AssetStreamAdaptor> stream(new AssetStreamAdaptor(asset));
+
+ if (stream.get()->read(jpegSignature.get(), kJpegSignatureSize) != kJpegSignatureSize) {
+ // Rewind the stream.
+ stream.get()->rewind();
+
+ ALOGI("Corrupted image.");
+ return NULL;
+ }
+
+ // Rewind the stream.
+ stream.get()->rewind();
+
+ if (memcmp(jpegSignature.get(), kJpegSignatureChars, kJpegSignatureSize) == 0) {
+ ALOGI("Should be a JPEG stream.");
+ return NULL;
+ }
+
+ // Try to parse from the given stream.
+ jobject result = getRawAttributes(env, stream.get(), false);
+
+ // Rewind the stream for the chance to read JPEG.
+ if (result == NULL) {
+ stream.get()->rewind();
+ }
+ return result;
+}
+
+static jobject ExifInterface_getRawAttributesFromFileDescriptor(
+ JNIEnv* env, jclass /* clazz */, jobject jfileDescriptor) {
+ std::unique_ptr<char[]> jpegSignature(new char[kJpegSignatureSize]);
+ if (jpegSignature.get() == NULL) {
+ ALOGE("No enough memory to parse");
+ return NULL;
+ }
+
+ int fd = jniGetFDFromFileDescriptor(env, jfileDescriptor);
+ if (fd < 0) {
+ ALOGI("Invalid file descriptor");
+ return NULL;
+ }
+
+ // Restore the file descriptor's offset on exiting this function.
+ AutoFDSeek autoRestore(fd);
+
+ int dupFd = dup(fd);
+
+ FILE* file = fdopen(dupFd, "r");
+ if (file == NULL) {
+ ALOGI("Failed to open the file descriptor");
+ return NULL;
+ }
+
+ if (fgets(jpegSignature.get(), kJpegSignatureSize, file) == NULL) {
+ ALOGI("Corrupted image.");
+ return NULL;
+ }
+
+ if (memcmp(jpegSignature.get(), kJpegSignatureChars, kJpegSignatureSize) == 0) {
+ ALOGI("Should be a JPEG stream.");
+ return NULL;
+ }
+
+ // Rewind the file descriptor.
+ fseek(file, 0L, SEEK_SET);
+
+ std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file,
+ SkFILEStream::kCallerPasses_Ownership));
+ return getRawAttributes(env, fileStream.get(), false);
+}
+
+static jobject ExifInterface_getRawAttributesFromInputStream(
+ JNIEnv* env, jclass /* clazz */, jobject jinputStream) {
+ jbyteArray byteArray = env->NewByteArray(8*1024);
+ ScopedLocalRef<jbyteArray> scoper(env, byteArray);
+ std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, jinputStream, scoper.get()));
+ return getRawAttributes(env, stream.get(), true);
}
} // extern "C"
@@ -261,9 +407,14 @@
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- { "initRawNative", "()V", (void *)ExifInterface_initRaw },
- { "getRawAttributesNative", "(Ljava/io/FileDescriptor;)Ljava/util/HashMap;",
- (void*)ExifInterface_getRawMetadata },
+ { "nativeInitRaw", "()V", (void *)ExifInterface_initRaw },
+ { "nativeGetThumbnailFromAsset", "(JII)[B", (void *)ExifInterface_getThumbnailFromAsset },
+ { "nativeGetRawAttributesFromAsset", "(J)Ljava/util/HashMap;",
+ (void*)ExifInterface_getRawAttributesFromAsset },
+ { "nativeGetRawAttributesFromFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/util/HashMap;",
+ (void*)ExifInterface_getRawAttributesFromFileDescriptor },
+ { "nativeGetRawAttributesFromInputStream", "(Ljava/io/InputStream;)Ljava/util/HashMap;",
+ (void*)ExifInterface_getRawAttributesFromInputStream },
};
int register_android_media_ExifInterface(JNIEnv *env) {
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 9e90a19..c3993ae 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -16,6 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ImageReader_JNI"
+#include "android_media_Utils.h"
#include <utils/Log.h>
#include <utils/misc.h>
#include <utils/List.h>
@@ -23,7 +24,6 @@
#include <cstdio>
-#include <gui/CpuConsumer.h>
#include <gui/BufferItemConsumer.h>
#include <gui/Surface.h>
#include <camera3.h>
@@ -37,8 +37,6 @@
#include <stdint.h>
#include <inttypes.h>
-#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
-
#define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID "mNativeContext"
#define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID "mNativeBuffer"
#define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID "mTimestamp"
@@ -47,9 +45,6 @@
using namespace android;
-enum {
- IMAGE_READER_MAX_NUM_PLANES = 3,
-};
enum {
ACQUIRE_SUCCESS = 0,
@@ -65,6 +60,7 @@
static struct {
jfieldID mNativeBuffer;
jfieldID mTimestamp;
+ jfieldID mPlanes;
} gSurfaceImageClassInfo;
static struct {
@@ -89,21 +85,12 @@
virtual void onFrameAvailable(const BufferItem& item);
- CpuConsumer::LockedBuffer* getLockedBuffer();
- void returnLockedBuffer(CpuConsumer::LockedBuffer* buffer);
+ BufferItem* getBufferItem();
+ void returnBufferItem(BufferItem* buffer);
- BufferItem* getOpaqueBuffer();
- void returnOpaqueBuffer(BufferItem* buffer);
- void setCpuConsumer(const sp<CpuConsumer>& consumer) { mConsumer = consumer; }
- CpuConsumer* getCpuConsumer() { return mConsumer.get(); }
-
- void setOpaqueConsumer(const sp<BufferItemConsumer>& consumer) { mOpaqueConsumer = consumer; }
- BufferItemConsumer* getOpaqueConsumer() { return mOpaqueConsumer.get(); }
- // This is the only opaque format exposed in the ImageFormat public API.
- // Note that we do support CPU access for HAL_PIXEL_FORMAT_RAW_OPAQUE
- // (ImageFormat#RAW_PRIVATE) so it doesn't count as opaque here.
- bool isOpaque() { return mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; }
+ void setBufferConsumer(const sp<BufferItemConsumer>& consumer) { mConsumer = consumer; }
+ BufferItemConsumer* getBufferConsumer() { return mConsumer.get(); }
void setProducer(const sp<IGraphicBufferProducer>& producer) { mProducer = producer; }
IGraphicBufferProducer* getProducer() { return mProducer.get(); }
@@ -124,10 +111,8 @@
static JNIEnv* getJNIEnv(bool* needsDetach);
static void detachJNI();
- List<CpuConsumer::LockedBuffer*> mBuffers;
- List<BufferItem*> mOpaqueBuffers;
- sp<CpuConsumer> mConsumer;
- sp<BufferItemConsumer> mOpaqueConsumer;
+ List<BufferItem*> mBuffers;
+ sp<BufferItemConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
jobject mWeakThiz;
jclass mClazz;
@@ -140,12 +125,14 @@
JNIImageReaderContext::JNIImageReaderContext(JNIEnv* env,
jobject weakThiz, jclass clazz, int maxImages) :
mWeakThiz(env->NewGlobalRef(weakThiz)),
- mClazz((jclass)env->NewGlobalRef(clazz)) {
+ mClazz((jclass)env->NewGlobalRef(clazz)),
+ mFormat(0),
+ mDataSpace(HAL_DATASPACE_UNKNOWN),
+ mWidth(-1),
+ mHeight(-1) {
for (int i = 0; i < maxImages; i++) {
- CpuConsumer::LockedBuffer *buffer = new CpuConsumer::LockedBuffer;
- BufferItem* opaqueBuffer = new BufferItem;
+ BufferItem* buffer = new BufferItem;
mBuffers.push_back(buffer);
- mOpaqueBuffers.push_back(opaqueBuffer);
}
}
@@ -174,36 +161,21 @@
}
}
-CpuConsumer::LockedBuffer* JNIImageReaderContext::getLockedBuffer() {
+BufferItem* JNIImageReaderContext::getBufferItem() {
if (mBuffers.empty()) {
return NULL;
}
- // Return a LockedBuffer pointer and remove it from the list
- List<CpuConsumer::LockedBuffer*>::iterator it = mBuffers.begin();
- CpuConsumer::LockedBuffer* buffer = *it;
+ // Return a BufferItem pointer and remove it from the list
+ List<BufferItem*>::iterator it = mBuffers.begin();
+ BufferItem* buffer = *it;
mBuffers.erase(it);
return buffer;
}
-void JNIImageReaderContext::returnLockedBuffer(CpuConsumer::LockedBuffer* buffer) {
+void JNIImageReaderContext::returnBufferItem(BufferItem* buffer) {
mBuffers.push_back(buffer);
}
-BufferItem* JNIImageReaderContext::getOpaqueBuffer() {
- if (mOpaqueBuffers.empty()) {
- return NULL;
- }
- // Return an opaque buffer pointer and remove it from the list
- List<BufferItem*>::iterator it = mOpaqueBuffers.begin();
- BufferItem* buffer = *it;
- mOpaqueBuffers.erase(it);
- return buffer;
-}
-
-void JNIImageReaderContext::returnOpaqueBuffer(BufferItem* buffer) {
- mOpaqueBuffers.push_back(buffer);
-}
-
JNIImageReaderContext::~JNIImageReaderContext() {
bool needsDetach = false;
JNIEnv* env = getJNIEnv(&needsDetach);
@@ -217,25 +189,15 @@
detachJNI();
}
- // Delete LockedBuffers
- for (List<CpuConsumer::LockedBuffer *>::iterator it = mBuffers.begin();
+ // Delete buffer items.
+ for (List<BufferItem *>::iterator it = mBuffers.begin();
it != mBuffers.end(); it++) {
delete *it;
}
- // Delete opaque buffers
- for (List<BufferItem *>::iterator it = mOpaqueBuffers.begin();
- it != mOpaqueBuffers.end(); it++) {
- delete *it;
- }
-
- mBuffers.clear();
if (mConsumer != 0) {
mConsumer.clear();
}
- if (mOpaqueConsumer != 0) {
- mOpaqueConsumer.clear();
- }
}
void JNIImageReaderContext::onFrameAvailable(const BufferItem& /*item*/)
@@ -257,11 +219,6 @@
extern "C" {
-static bool isFormatOpaque(int format) {
- // Only treat IMPLEMENTATION_DEFINED as an opaque format for now.
- return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-}
-
static JNIImageReaderContext* ImageReader_getContext(JNIEnv* env, jobject thiz)
{
JNIImageReaderContext *ctx;
@@ -270,24 +227,6 @@
return ctx;
}
-static CpuConsumer* ImageReader_getCpuConsumer(JNIEnv* env, jobject thiz)
-{
- ALOGV("%s:", __FUNCTION__);
- JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
- if (ctx == NULL) {
- jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
- return NULL;
- }
-
- if (ctx->isOpaque()) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Opaque ImageReader doesn't support this method");
- return NULL;
- }
-
- return ctx->getCpuConsumer();
-}
-
static IGraphicBufferProducer* ImageReader_getProducer(JNIEnv* env, jobject thiz)
{
ALOGV("%s:", __FUNCTION__);
@@ -315,411 +254,7 @@
reinterpret_cast<jlong>(ctx.get()));
}
-static CpuConsumer::LockedBuffer* Image_getLockedBuffer(JNIEnv* env, jobject image)
-{
- return reinterpret_cast<CpuConsumer::LockedBuffer*>(
- env->GetLongField(image, gSurfaceImageClassInfo.mNativeBuffer));
-}
-
-static void Image_setBuffer(JNIEnv* env, jobject thiz,
- const CpuConsumer::LockedBuffer* buffer)
-{
- env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
-}
-
-static void Image_setOpaqueBuffer(JNIEnv* env, jobject thiz,
- const BufferItem* buffer)
-{
- env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
-}
-
-static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer, bool usingRGBAOverride)
-{
- ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
- uint32_t size = 0;
- uint32_t width = buffer->width;
- uint8_t* jpegBuffer = buffer->data;
-
- if (usingRGBAOverride) {
- width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
- }
-
- // First check for JPEG transport header at the end of the buffer
- uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
- struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
- if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
- size = blob->jpeg_size;
- ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
- }
-
- // failed to find size, default to whole buffer
- if (size == 0) {
- /*
- * This is a problem because not including the JPEG header
- * means that in certain rare situations a regular JPEG blob
- * will be misidentified as having a header, in which case
- * we will get a garbage size value.
- */
- ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
- __FUNCTION__, width);
- size = width;
- }
-
- return size;
-}
-
-static bool usingRGBAToJpegOverride(int32_t bufferFormat, int32_t readerCtxFormat) {
- return readerCtxFormat == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888;
-}
-
-static int32_t applyFormatOverrides(int32_t bufferFormat, int32_t readerCtxFormat)
-{
- // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
- // write limitations for some platforms (b/17379185).
- if (usingRGBAToJpegOverride(bufferFormat, readerCtxFormat)) {
- return HAL_PIXEL_FORMAT_BLOB;
- }
- return bufferFormat;
-}
-
-static void Image_getLockedBufferInfo(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
- uint8_t **base, uint32_t *size, int32_t readerFormat)
-{
- ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
- ALOG_ASSERT(base != NULL, "base is NULL!!!");
- ALOG_ASSERT(size != NULL, "size is NULL!!!");
- ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
-
- ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
-
- uint32_t dataSize, ySize, cSize, cStride;
- uint8_t *cb, *cr;
- uint8_t *pData = NULL;
- int bytesPerPixel = 0;
-
- dataSize = ySize = cSize = cStride = 0;
- int32_t fmt = buffer->flexFormat;
-
- bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, readerFormat);
- fmt = applyFormatOverrides(fmt, readerFormat);
- switch (fmt) {
- case HAL_PIXEL_FORMAT_YCbCr_420_888:
- pData =
- (idx == 0) ?
- buffer->data :
- (idx == 1) ?
- buffer->dataCb :
- buffer->dataCr;
- // only map until last pixel
- if (idx == 0) {
- dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
- } else {
- dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
- buffer->chromaStep * (buffer->width / 2 - 1) + 1;
- }
- break;
- // NV21
- case HAL_PIXEL_FORMAT_YCrCb_420_SP:
- cr = buffer->data + (buffer->stride * buffer->height);
- cb = cr + 1;
- // only map until last pixel
- ySize = buffer->width * (buffer->height - 1) + buffer->width;
- cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
-
- pData =
- (idx == 0) ?
- buffer->data :
- (idx == 1) ?
- cb:
- cr;
-
- dataSize = (idx == 0) ? ySize : cSize;
- break;
- case HAL_PIXEL_FORMAT_YV12:
- // Y and C stride need to be 16 pixel aligned.
- LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
- "Stride is not 16 pixel aligned %d", buffer->stride);
-
- ySize = buffer->stride * buffer->height;
- cStride = ALIGN(buffer->stride / 2, 16);
- cr = buffer->data + ySize;
- cSize = cStride * buffer->height / 2;
- cb = cr + cSize;
-
- pData =
- (idx == 0) ?
- buffer->data :
- (idx == 1) ?
- cb :
- cr;
- dataSize = (idx == 0) ? ySize : cSize;
- break;
- case HAL_PIXEL_FORMAT_Y8:
- // Single plane, 8bpp.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height;
- break;
- case HAL_PIXEL_FORMAT_Y16:
- bytesPerPixel = 2;
- // Single plane, 16bpp, strides are specified in pixels, not in bytes
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- break;
- case HAL_PIXEL_FORMAT_BLOB:
- // Used for JPEG data, height must be 1, width == size, single plane.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- ALOG_ASSERT(buffer->height == 1,
- "JPEG should has height value one but got %d", buffer->height);
-
- pData = buffer->data;
- dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
- break;
- case HAL_PIXEL_FORMAT_RAW16:
- // Single plane 16bpp bayer data.
- bytesPerPixel = 2;
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- break;
- case HAL_PIXEL_FORMAT_RAW_OPAQUE:
- // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- ALOG_ASSERT(buffer->height == 1,
- "RAW_PRIVATE should has height value one but got %d", buffer->height);
- pData = buffer->data;
- dataSize = buffer->width;
- break;
- case HAL_PIXEL_FORMAT_RAW10:
- // Single plane 10bpp bayer data.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- LOG_ALWAYS_FATAL_IF(buffer->width % 4,
- "Width is not multiple of 4 %d", buffer->width);
- LOG_ALWAYS_FATAL_IF(buffer->height % 2,
- "Height is not even %d", buffer->height);
- LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
- "stride (%d) should be at least %d",
- buffer->stride, buffer->width * 10 / 8);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height;
- break;
- case HAL_PIXEL_FORMAT_RAW12:
- // Single plane 10bpp bayer data.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- LOG_ALWAYS_FATAL_IF(buffer->width % 4,
- "Width is not multiple of 4 %d", buffer->width);
- LOG_ALWAYS_FATAL_IF(buffer->height % 2,
- "Height is not even %d", buffer->height);
- LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 12 / 8),
- "stride (%d) should be at least %d",
- buffer->stride, buffer->width * 12 / 8);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height;
- break;
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- // Single plane, 32bpp.
- bytesPerPixel = 4;
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- break;
- case HAL_PIXEL_FORMAT_RGB_565:
- // Single plane, 16bpp.
- bytesPerPixel = 2;
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- break;
- case HAL_PIXEL_FORMAT_RGB_888:
- // Single plane, 24bpp.
- bytesPerPixel = 3;
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- break;
- default:
- jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
- "Pixel format: 0x%x is unsupported", fmt);
- break;
- }
-
- *base = pData;
- *size = dataSize;
-}
-
-static jint Image_imageGetPixelStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
- int32_t halReaderFormat)
-{
- ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
- ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0), "Index is out of range:%d", idx);
-
- int pixelStride = 0;
- ALOG_ASSERT(buffer != NULL, "buffer is NULL");
-
- int32_t fmt = buffer->flexFormat;
-
- fmt = applyFormatOverrides(fmt, halReaderFormat);
-
- switch (fmt) {
- case HAL_PIXEL_FORMAT_YCbCr_420_888:
- pixelStride = (idx == 0) ? 1 : buffer->chromaStep;
- break;
- case HAL_PIXEL_FORMAT_YCrCb_420_SP:
- pixelStride = (idx == 0) ? 1 : 2;
- break;
- case HAL_PIXEL_FORMAT_Y8:
- // Single plane 8bpp data.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pixelStride = 1;
- break;
- case HAL_PIXEL_FORMAT_YV12:
- pixelStride = 1;
- break;
- case HAL_PIXEL_FORMAT_BLOB:
- case HAL_PIXEL_FORMAT_RAW10:
- case HAL_PIXEL_FORMAT_RAW12:
- // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
- // those are single plane data with pixel stride 0 since they don't really have a
- // well defined pixel stride
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pixelStride = 0;
- break;
- case HAL_PIXEL_FORMAT_Y16:
- case HAL_PIXEL_FORMAT_RAW16:
- case HAL_PIXEL_FORMAT_RGB_565:
- // Single plane 16bpp data.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pixelStride = 2;
- break;
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pixelStride = 4;
- break;
- case HAL_PIXEL_FORMAT_RGB_888:
- // Single plane, 24bpp.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pixelStride = 3;
- break;
- case HAL_PIXEL_FORMAT_RAW_OPAQUE:
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pixelStride = 0; // RAW OPAQUE doesn't have pixel stride
- break;
- default:
- jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
- "Pixel format: 0x%x is unsupported", fmt);
- break;
- }
-
- return pixelStride;
-}
-
-static jint Image_imageGetRowStride(JNIEnv* env, CpuConsumer::LockedBuffer* buffer, int idx,
- int32_t halReaderFormat)
-{
- ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
- ALOG_ASSERT((idx < IMAGE_READER_MAX_NUM_PLANES) && (idx >= 0));
-
- int rowStride = 0;
- ALOG_ASSERT(buffer != NULL, "buffer is NULL");
-
- int32_t fmt = buffer->flexFormat;
-
- fmt = applyFormatOverrides(fmt, halReaderFormat);
-
- switch (fmt) {
- case HAL_PIXEL_FORMAT_YCbCr_420_888:
- rowStride = (idx == 0) ? buffer->stride : buffer->chromaStride;
- break;
- case HAL_PIXEL_FORMAT_YCrCb_420_SP:
- rowStride = buffer->width;
- break;
- case HAL_PIXEL_FORMAT_YV12:
- LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
- "Stride is not 16 pixel aligned %d", buffer->stride);
- rowStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
- break;
- case HAL_PIXEL_FORMAT_BLOB:
- // Blob is used for JPEG data. It is single plane and has 0 row stride and
- // 0 pixel stride
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- rowStride = 0;
- break;
- case HAL_PIXEL_FORMAT_RAW10:
- case HAL_PIXEL_FORMAT_RAW12:
- // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- rowStride = buffer->stride;
- break;
- case HAL_PIXEL_FORMAT_Y8:
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
- "Stride is not 16 pixel aligned %d", buffer->stride);
- rowStride = buffer->stride;
- break;
- case HAL_PIXEL_FORMAT_Y16:
- case HAL_PIXEL_FORMAT_RAW16:
- // In native side, strides are specified in pixels, not in bytes.
- // Single plane 16bpp bayer data. even width/height,
- // row stride multiple of 16 pixels (32 bytes)
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
- "Stride is not 16 pixel aligned %d", buffer->stride);
- rowStride = buffer->stride * 2;
- break;
- case HAL_PIXEL_FORMAT_RGB_565:
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- rowStride = buffer->stride * 2;
- break;
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- rowStride = buffer->stride * 4;
- break;
- case HAL_PIXEL_FORMAT_RGB_888:
- // Single plane, 24bpp.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- rowStride = buffer->stride * 3;
- break;
- case HAL_PIXEL_FORMAT_RAW_OPAQUE:
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- rowStride = 0; // RAW OPAQUE doesn't have row stride
- break;
- default:
- ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
- jniThrowException(env, "java/lang/UnsupportedOperationException",
- "unsupported buffer format");
- break;
- }
-
- return rowStride;
-}
-
-static int Image_getBufferWidth(CpuConsumer::LockedBuffer* buffer) {
- if (buffer == NULL) return -1;
-
- if (!buffer->crop.isEmpty()) {
- return buffer->crop.getWidth();
- }
- return buffer->width;
-}
-
-static int Image_getBufferHeight(CpuConsumer::LockedBuffer* buffer) {
- if (buffer == NULL) return -1;
-
- if (!buffer->crop.isEmpty()) {
- return buffer->crop.getHeight();
- }
- return buffer->height;
-}
-
-// --------------------------Methods for opaque Image and ImageReader----------
-
-static BufferItemConsumer* ImageReader_getOpaqueConsumer(JNIEnv* env, jobject thiz)
+static BufferItemConsumer* ImageReader_getBufferConsumer(JNIEnv* env, jobject thiz)
{
ALOGV("%s:", __FUNCTION__);
JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
@@ -728,40 +263,21 @@
return NULL;
}
- if (!ctx->isOpaque()) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Non-opaque ImageReader doesn't support this method");
- }
-
- return ctx->getOpaqueConsumer();
+ return ctx->getBufferConsumer();
}
-static BufferItem* Image_getOpaqueBuffer(JNIEnv* env, jobject image)
+static void Image_setBufferItem(JNIEnv* env, jobject thiz,
+ const BufferItem* buffer)
+{
+ env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
+}
+
+static BufferItem* Image_getBufferItem(JNIEnv* env, jobject image)
{
return reinterpret_cast<BufferItem*>(
env->GetLongField(image, gSurfaceImageClassInfo.mNativeBuffer));
}
-static int Image_getOpaqueBufferWidth(BufferItem* buffer) {
- if (buffer == NULL) return -1;
-
- if (!buffer->mCrop.isEmpty()) {
- return buffer->mCrop.getWidth();
- }
- return buffer->mGraphicBuffer->getWidth();
-}
-
-static int Image_getOpaqueBufferHeight(BufferItem* buffer) {
- if (buffer == NULL) return -1;
-
- if (!buffer->mCrop.isEmpty()) {
- return buffer->mCrop.getHeight();
- }
-
- return buffer->mGraphicBuffer->getHeight();
-}
-
-
// ----------------------------------------------------------------------------
@@ -784,6 +300,11 @@
"can't find android/graphics/ImageReader.%s",
ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID);
+ gSurfaceImageClassInfo.mPlanes = env->GetFieldID(
+ imageClazz, "mPlanes", "[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;");
+ LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mPlanes == NULL,
+ "can't find android/media/ImageReader$ReaderSurfaceImage.mPlanes");
+
gImageReaderClassInfo.mNativeContext = env->GetFieldID(
clazz, ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID, "J");
LOG_ALWAYS_FATAL_IF(gImageReaderClassInfo.mNativeContext == NULL,
@@ -800,7 +321,7 @@
// FindClass only gives a local reference of jclass object.
gSurfacePlaneClassInfo.clazz = (jclass) env->NewGlobalRef(planeClazz);
gSurfacePlaneClassInfo.ctor = env->GetMethodID(gSurfacePlaneClassInfo.clazz, "<init>",
- "(Landroid/media/ImageReader$SurfaceImage;III)V");
+ "(Landroid/media/ImageReader$SurfaceImage;IILjava/nio/ByteBuffer;)V");
LOG_ALWAYS_FATAL_IF(gSurfacePlaneClassInfo.ctor == NULL,
"Can not find SurfacePlane constructor");
}
@@ -831,81 +352,52 @@
sp<IGraphicBufferProducer> gbProducer;
sp<IGraphicBufferConsumer> gbConsumer;
BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
- sp<ConsumerBase> consumer;
- sp<CpuConsumer> cpuConsumer;
- sp<BufferItemConsumer> opaqueConsumer;
+ sp<BufferItemConsumer> bufferConsumer;
String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
width, height, format, maxImages, getpid(),
createProcessUniqueId());
+ uint32_t consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+
if (isFormatOpaque(nativeFormat)) {
// Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
// encoding. The only possibility will be ZSL output.
- opaqueConsumer =
- new BufferItemConsumer(gbConsumer, GRALLOC_USAGE_SW_READ_NEVER, maxImages,
- /*controlledByApp*/true);
- if (opaqueConsumer == NULL) {
- jniThrowRuntimeException(env, "Failed to allocate native opaque consumer");
- return;
- }
- ctx->setOpaqueConsumer(opaqueConsumer);
- opaqueConsumer->setName(consumerName);
- consumer = opaqueConsumer;
- } else {
- cpuConsumer = new CpuConsumer(gbConsumer, maxImages, /*controlledByApp*/true);
- // TODO: throw dvm exOutOfMemoryError?
- if (cpuConsumer == NULL) {
- jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
- return;
- }
- ctx->setCpuConsumer(cpuConsumer);
- cpuConsumer->setName(consumerName);
- consumer = cpuConsumer;
+ consumerUsage = GRALLOC_USAGE_SW_READ_NEVER;
}
+ bufferConsumer = new BufferItemConsumer(gbConsumer, consumerUsage, maxImages,
+ /*controlledByApp*/true);
+ if (bufferConsumer == nullptr) {
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "Failed to allocate native buffer consumer for format 0x%x", nativeFormat);
+ return;
+ }
+ ctx->setBufferConsumer(bufferConsumer);
+ bufferConsumer->setName(consumerName);
ctx->setProducer(gbProducer);
- consumer->setFrameAvailableListener(ctx);
+ bufferConsumer->setFrameAvailableListener(ctx);
ImageReader_setNativeContext(env, thiz, ctx);
ctx->setBufferFormat(nativeFormat);
ctx->setBufferDataspace(nativeDataspace);
ctx->setBufferWidth(width);
ctx->setBufferHeight(height);
- // Set the width/height/format/dataspace to the CpuConsumer
- // TODO: below code can be simplified once b/19977701 is fixed.
- if (isFormatOpaque(nativeFormat)) {
- res = opaqueConsumer->setDefaultBufferSize(width, height);
- if (res != OK) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to set opaque consumer buffer size");
- return;
- }
- res = opaqueConsumer->setDefaultBufferFormat(nativeFormat);
- if (res != OK) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to set opaque consumer buffer format");
- }
- res = opaqueConsumer->setDefaultBufferDataSpace(nativeDataspace);
- if (res != OK) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to set opaque consumer buffer dataSpace");
- }
- } else {
- res = cpuConsumer->setDefaultBufferSize(width, height);
- if (res != OK) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to set CpuConsumer buffer size");
- return;
- }
- res = cpuConsumer->setDefaultBufferFormat(nativeFormat);
- if (res != OK) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to set CpuConsumer buffer format");
- }
- res = cpuConsumer->setDefaultBufferDataSpace(nativeDataspace);
- if (res != OK) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to set CpuConsumer buffer dataSpace");
- }
+ // Set the width/height/format/dataspace to the bufferConsumer.
+ res = bufferConsumer->setDefaultBufferSize(width, height);
+ if (res != OK) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Failed to set buffer consumer default size (%dx%d) for format 0x%x",
+ width, height, nativeFormat);
+ return;
+ }
+ res = bufferConsumer->setDefaultBufferFormat(nativeFormat);
+ if (res != OK) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Failed to set buffer consumer default format 0x%x", nativeFormat);
+ }
+ res = bufferConsumer->setDefaultBufferDataSpace(nativeDataspace);
+ if (res != OK) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Failed to set buffer consumer default dataSpace 0x%x", nativeDataspace);
}
}
@@ -919,12 +411,8 @@
return;
}
- ConsumerBase* consumer = NULL;
- if (ctx->isOpaque()) {
- consumer = ImageReader_getOpaqueConsumer(env, thiz);
- } else {
- consumer = ImageReader_getCpuConsumer(env, thiz);
- }
+ BufferItemConsumer* consumer = NULL;
+ consumer = ImageReader_getBufferConsumer(env, thiz);
if (consumer != NULL) {
consumer->abandon();
@@ -933,6 +421,39 @@
ImageReader_setNativeContext(env, thiz, NULL);
}
+static sp<Fence> Image_unlockIfLocked(JNIEnv* env, jobject image) {
+ ALOGV("%s", __FUNCTION__);
+ BufferItem* buffer = Image_getBufferItem(env, image);
+ if (buffer == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Image is not initialized");
+ return Fence::NO_FENCE;
+ }
+
+ // Is locked?
+ bool wasBufferLocked = false;
+ jobject planes = NULL;
+ if (!isFormatOpaque(buffer->mGraphicBuffer->getPixelFormat())) {
+ planes = env->GetObjectField(image, gSurfaceImageClassInfo.mPlanes);
+ }
+ wasBufferLocked = (planes != NULL);
+ if (wasBufferLocked) {
+ status_t res = OK;
+ int fenceFd = -1;
+ if (wasBufferLocked) {
+ res = buffer->mGraphicBuffer->unlockAsync(&fenceFd);
+ if (res != OK) {
+ jniThrowRuntimeException(env, "unlock buffer failed");
+ return Fence::NO_FENCE;
+ }
+ }
+ sp<Fence> releaseFence = new Fence(fenceFd);
+ return releaseFence;
+ ALOGV("Successfully unlocked the image");
+ }
+ return Fence::NO_FENCE;
+}
+
static void ImageReader_imageRelease(JNIEnv* env, jobject thiz, jobject image)
{
ALOGV("%s:", __FUNCTION__);
@@ -942,156 +463,18 @@
return;
}
- if (ctx->isOpaque()) {
- BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
- BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, image);
- opaqueConsumer->releaseBuffer(*opaqueBuffer); // Not using fence for now.
- Image_setOpaqueBuffer(env, image, NULL);
- ctx->returnOpaqueBuffer(opaqueBuffer);
- ALOGV("%s: Opaque Image has been released", __FUNCTION__);
- } else {
- CpuConsumer* consumer = ctx->getCpuConsumer();
- CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, image);
- if (!buffer) {
- // Release an already closed image is harmless.
- return;
- }
- consumer->unlockBuffer(*buffer);
- Image_setBuffer(env, image, NULL);
- ctx->returnLockedBuffer(buffer);
- ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
- }
-}
-
-static jint ImageReader_opaqueImageSetup(JNIEnv* env, JNIImageReaderContext* ctx, jobject image) {
- ALOGV("%s:", __FUNCTION__);
- if (ctx == NULL || !ctx->isOpaque()) {
- jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
- return -1;
+ BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
+ BufferItem* buffer = Image_getBufferItem(env, image);
+ if (buffer == nullptr) {
+ // Release an already closed image is harmless.
+ return;
}
- BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
- BufferItem* buffer = ctx->getOpaqueBuffer();
- if (buffer == NULL) {
- ALOGW("Unable to acquire a buffer item, very likely client tried to acquire more than"
- " maxImages buffers");
- return ACQUIRE_MAX_IMAGES;
- }
-
- status_t res = opaqueConsumer->acquireBuffer(buffer, 0);
- if (res != OK) {
- ctx->returnOpaqueBuffer(buffer);
- if (res == INVALID_OPERATION) {
- // Max number of images were already acquired.
- ALOGE("%s: Max number of buffers allowed are already acquired : %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return ACQUIRE_MAX_IMAGES;
- } else {
- ALOGE("%s: Acquire image failed with error: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return ACQUIRE_NO_BUFFERS;
- }
- }
-
- // Set SurfaceImage instance member variables
- Image_setOpaqueBuffer(env, image, buffer);
- env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
- static_cast<jlong>(buffer->mTimestamp));
-
- return ACQUIRE_SUCCESS;
-}
-
-static jint ImageReader_lockedImageSetup(JNIEnv* env, JNIImageReaderContext* ctx, jobject image) {
- CpuConsumer* consumer = ctx->getCpuConsumer();
- CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer();
- if (buffer == NULL) {
- ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
- " maxImages buffers");
- return ACQUIRE_MAX_IMAGES;
- }
- status_t res = consumer->lockNextBuffer(buffer);
- if (res != NO_ERROR) {
- ctx->returnLockedBuffer(buffer);
- if (res != BAD_VALUE /*no buffers*/) {
- if (res == NOT_ENOUGH_DATA) {
- return ACQUIRE_MAX_IMAGES;
- } else {
- ALOGE("%s Fail to lockNextBuffer with error: %d ",
- __FUNCTION__, res);
- jniThrowExceptionFmt(env, "java/lang/AssertionError",
- "Unknown error (%d) when we tried to lock buffer.",
- res);
- }
- }
- return ACQUIRE_NO_BUFFERS;
- }
-
- if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
- jniThrowException(env, "java/lang/UnsupportedOperationException",
- "NV21 format is not supported by ImageReader");
- return -1;
- }
-
- // Check if the left-top corner of the crop rect is origin, we currently assume this point is
- // zero, will revist this once this assumption turns out problematic.
- Point lt = buffer->crop.leftTop();
- if (lt.x != 0 || lt.y != 0) {
- jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
- "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
- return -1;
- }
-
- // Check if the producer buffer configurations match what ImageReader configured.
- int outputWidth = Image_getBufferWidth(buffer);
- int outputHeight = Image_getBufferHeight(buffer);
-
- int imgReaderFmt = ctx->getBufferFormat();
- int imageReaderWidth = ctx->getBufferWidth();
- int imageReaderHeight = ctx->getBufferHeight();
- if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) &&
- (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) {
- ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
- __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
- }
-
- int bufFmt = buffer->format;
- if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
- bufFmt = buffer->flexFormat;
- }
- if (imgReaderFmt != bufFmt) {
- if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
- HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
- // Special casing for when producer switches to a format compatible with flexible YUV
- // (HAL_PIXEL_FORMAT_YCbCr_420_888).
- ctx->setBufferFormat(bufFmt);
- ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
- } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB && bufFmt == HAL_PIXEL_FORMAT_RGBA_8888) {
- // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
- // write limitations for (b/17379185).
- ALOGD("%s: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.", __FUNCTION__);
- } else {
- // Return the buffer to the queue.
- consumer->unlockBuffer(*buffer);
- ctx->returnLockedBuffer(buffer);
-
- // Throw exception
- ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
- buffer->format, ctx->getBufferFormat());
- String8 msg;
- msg.appendFormat("The producer output buffer format 0x%x doesn't "
- "match the ImageReader's configured buffer format 0x%x.",
- bufFmt, ctx->getBufferFormat());
- jniThrowException(env, "java/lang/UnsupportedOperationException",
- msg.string());
- return -1;
- }
- }
- // Set SurfaceImage instance member variables
- Image_setBuffer(env, image, buffer);
- env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
- static_cast<jlong>(buffer->timestamp));
-
- return ACQUIRE_SUCCESS;
+ sp<Fence> releaseFence = Image_unlockIfLocked(env, image);
+ bufferConsumer->releaseBuffer(*buffer, releaseFence);
+ Image_setBufferItem(env, image, NULL);
+ ctx->returnBufferItem(buffer);
+ ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
}
static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
@@ -1103,11 +486,99 @@
return -1;
}
- if (ctx->isOpaque()) {
- return ImageReader_opaqueImageSetup(env, ctx, image);
- } else {
- return ImageReader_lockedImageSetup(env, ctx, image);
+ BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
+ BufferItem* buffer = ctx->getBufferItem();
+ if (buffer == NULL) {
+ ALOGW("Unable to acquire a buffer item, very likely client tried to acquire more than"
+ " maxImages buffers");
+ return ACQUIRE_MAX_IMAGES;
}
+
+ status_t res = bufferConsumer->acquireBuffer(buffer, 0);
+ if (res != OK) {
+ ctx->returnBufferItem(buffer);
+ if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
+ if (res == INVALID_OPERATION) {
+ // Max number of images were already acquired.
+ ALOGE("%s: Max number of buffers allowed are already acquired : %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return ACQUIRE_MAX_IMAGES;
+ } else {
+ ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+ "Unknown error (%d) when we tried to acquire an image.",
+ res);
+ return ACQUIRE_NO_BUFFERS;
+ }
+ }
+ // This isn't really an error case, as the application may acquire buffer at any time.
+ return ACQUIRE_NO_BUFFERS;
+ }
+
+ // Add some extra checks for non-opaque formats.
+ if (!isFormatOpaque(ctx->getBufferFormat())) {
+ // Check if the left-top corner of the crop rect is origin, we currently assume this point is
+ // zero, will revisit this once this assumption turns out problematic.
+ Point lt = buffer->mCrop.leftTop();
+ if (lt.x != 0 || lt.y != 0) {
+ jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+ "crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
+ return -1;
+ }
+
+ // Check if the producer buffer configurations match what ImageReader configured.
+ int outputWidth = getBufferWidth(buffer);
+ int outputHeight = getBufferHeight(buffer);
+
+ int imgReaderFmt = ctx->getBufferFormat();
+ int imageReaderWidth = ctx->getBufferWidth();
+ int imageReaderHeight = ctx->getBufferHeight();
+ int bufferFormat = buffer->mGraphicBuffer->getPixelFormat();
+ if ((bufferFormat != HAL_PIXEL_FORMAT_BLOB) && (imgReaderFmt != HAL_PIXEL_FORMAT_BLOB) &&
+ (imageReaderWidth != outputWidth || imageReaderHeight != outputHeight)) {
+ ALOGV("%s: Producer buffer size: %dx%d, doesn't match ImageReader configured size: %dx%d",
+ __FUNCTION__, outputWidth, outputHeight, imageReaderWidth, imageReaderHeight);
+ }
+ if (imgReaderFmt != bufferFormat) {
+ if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 &&
+ isPossiblyYUV(bufferFormat)) {
+ // Treat formats that are compatible with flexible YUV
+ // (HAL_PIXEL_FORMAT_YCbCr_420_888) as HAL_PIXEL_FORMAT_YCbCr_420_888.
+ ALOGV("%s: Treat buffer format to 0x%x as HAL_PIXEL_FORMAT_YCbCr_420_888",
+ __FUNCTION__, bufferFormat);
+ } else if (imgReaderFmt == HAL_PIXEL_FORMAT_BLOB &&
+ bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888) {
+ // Using HAL_PIXEL_FORMAT_RGBA_8888 Gralloc buffers containing JPEGs to get around
+ // SW write limitations for (b/17379185).
+ ALOGV("%s: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.", __FUNCTION__);
+ } else {
+ // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
+ // used anywhere yet.
+ bufferConsumer->releaseBuffer(*buffer);
+ ctx->returnBufferItem(buffer);
+
+ // Throw exception
+ ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
+ bufferFormat, ctx->getBufferFormat());
+ String8 msg;
+ msg.appendFormat("The producer output buffer format 0x%x doesn't "
+ "match the ImageReader's configured buffer format 0x%x.",
+ bufferFormat, ctx->getBufferFormat());
+ jniThrowException(env, "java/lang/UnsupportedOperationException",
+ msg.string());
+ return -1;
+ }
+ }
+
+ }
+
+ // Set SurfaceImage instance member variables
+ Image_setBufferItem(env, image, buffer);
+ env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
+ static_cast<jlong>(buffer->mTimestamp));
+
+ return ACQUIRE_SUCCESS;
}
static jint ImageReader_detachImage(JNIEnv* env, jobject thiz, jobject image) {
@@ -1118,29 +589,23 @@
return -1;
}
- status_t res = OK;
- if (!ctx->isOpaque()) {
- // TODO: Non-Opaque format detach is not implemented yet.
- jniThrowRuntimeException(env,
- "nativeDetachImage is not implemented yet for non-opaque format !!!");
- return -1;
- }
-
- BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
- BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, image);
- if (!opaqueBuffer) {
+ BufferItemConsumer* bufferConsumer = ctx->getBufferConsumer();
+ BufferItem* buffer = Image_getBufferItem(env, image);
+ if (!buffer) {
ALOGE(
- "Opaque Image already released and can not be detached from ImageReader!!!");
+ "Image already released and can not be detached from ImageReader!!!");
jniThrowException(env, "java/lang/IllegalStateException",
- "Opaque Image detach from ImageReader failed: buffer was already released");
+ "Image detach from ImageReader failed: buffer was already released");
return -1;
}
- res = opaqueConsumer->detachBuffer(opaqueBuffer->mSlot);
+ status_t res = OK;
+ Image_unlockIfLocked(env, image);
+ res = bufferConsumer->detachBuffer(buffer->mSlot);
if (res != OK) {
- ALOGE("Opaque Image detach failed: %s (%d)!!!", strerror(-res), res);
+ ALOGE("Image detach failed: %s (%d)!!!", strerror(-res), res);
jniThrowRuntimeException(env,
- "nativeDetachImage failed for opaque image!!!");
+ "nativeDetachImage failed for image!!!");
return res;
}
return OK;
@@ -1152,7 +617,7 @@
IGraphicBufferProducer* gbp = ImageReader_getProducer(env, thiz);
if (gbp == NULL) {
- jniThrowRuntimeException(env, "CpuConsumer is uninitialized");
+ jniThrowRuntimeException(env, "Buffer consumer is uninitialized");
return NULL;
}
@@ -1160,98 +625,115 @@
return android_view_Surface_createFromIGraphicBufferProducer(env, gbp);
}
-static jobject Image_createSurfacePlane(JNIEnv* env, jobject thiz, int idx, int readerFormat)
+static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image) {
+ ALOGV("%s", __FUNCTION__);
+ BufferItem* buffer = Image_getBufferItem(env, thiz);
+ if (buffer == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Image is not initialized");
+ return;
+ }
+
+ status_t res = lockImageFromBuffer(buffer,
+ GRALLOC_USAGE_SW_READ_OFTEN, buffer->mFence->dup(), image);
+ if (res != OK) {
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "lock buffer failed for format 0x%x",
+ buffer->mGraphicBuffer->getPixelFormat());
+ return;
+ }
+
+ // Carry over some fields from BufferItem.
+ image->crop = buffer->mCrop;
+ image->transform = buffer->mTransform;
+ image->scalingMode = buffer->mScalingMode;
+ image->timestamp = buffer->mTimestamp;
+ image->dataSpace = buffer->mDataSpace;
+ image->frameNumber = buffer->mFrameNumber;
+
+ ALOGV("%s: Successfully locked the image", __FUNCTION__);
+ // crop, transform, scalingMode, timestamp, and frameNumber should be set by producer,
+ // and we don't set them here.
+}
+
+static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
+ int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
+ ALOGV("%s", __FUNCTION__);
+
+ status_t res = getLockedImageInfo(buffer, idx, writerFormat, base, size,
+ pixelStride, rowStride);
+ if (res != OK) {
+ jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+ "Pixel format: 0x%x is unsupported", buffer->flexFormat);
+ }
+}
+
+static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
+ int numPlanes, int readerFormat)
{
- int rowStride, pixelStride;
+ ALOGV("%s: create SurfacePlane array with size %d", __FUNCTION__, numPlanes);
+ int rowStride = 0;
+ int pixelStride = 0;
+ uint8_t *pData = NULL;
+ uint32_t dataSize = 0;
+ jobject byteBuffer = NULL;
+
PublicFormat publicReaderFormat = static_cast<PublicFormat>(readerFormat);
int halReaderFormat = android_view_Surface_mapPublicFormatToHalFormat(
publicReaderFormat);
- ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
+ if (isFormatOpaque(halReaderFormat) && numPlanes > 0) {
+ String8 msg;
+ msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
+ " must be 0", halReaderFormat, numPlanes);
+ jniThrowException(env, "java/lang/IllegalArgumentException", msg.string());
+ return NULL;
+ }
+
+ jobjectArray surfacePlanes = env->NewObjectArray(numPlanes, gSurfacePlaneClassInfo.clazz,
+ /*initial_element*/NULL);
+ if (surfacePlanes == NULL) {
+ jniThrowRuntimeException(env, "Failed to create SurfacePlane arrays,"
+ " probably out of memory");
+ return NULL;
+ }
if (isFormatOpaque(halReaderFormat)) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Opaque images from Opaque ImageReader do not have any planes");
- return NULL;
+ // Return 0 element surface array.
+ return surfacePlanes;
}
- CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+ LockedImage lockedImg = LockedImage();
+ Image_getLockedImage(env, thiz, &lockedImg);
+ // Create all SurfacePlanes
+ for (int i = 0; i < numPlanes; i++) {
+ Image_getLockedImageInfo(env, &lockedImg, i, halReaderFormat,
+ &pData, &dataSize, &pixelStride, &rowStride);
+ byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
+ if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Failed to allocate ByteBuffer");
+ return NULL;
+ }
- ALOG_ASSERT(buffer != NULL);
- if (buffer == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
+ // Finally, create this SurfacePlane.
+ jobject surfacePlane = env->NewObject(gSurfacePlaneClassInfo.clazz,
+ gSurfacePlaneClassInfo.ctor, thiz, rowStride, pixelStride, byteBuffer);
+ env->SetObjectArrayElement(surfacePlanes, i, surfacePlane);
}
- rowStride = Image_imageGetRowStride(env, buffer, idx, halReaderFormat);
- pixelStride = Image_imageGetPixelStride(env, buffer, idx, halReaderFormat);
-
- jobject surfPlaneObj = env->NewObject(gSurfacePlaneClassInfo.clazz,
- gSurfacePlaneClassInfo.ctor, thiz, idx, rowStride, pixelStride);
-
- return surfPlaneObj;
+ return surfacePlanes;
}
-static jobject Image_getByteBuffer(JNIEnv* env, jobject thiz, int idx, int readerFormat)
+static jint Image_getWidth(JNIEnv* env, jobject thiz)
{
- uint8_t *base = NULL;
- uint32_t size = 0;
- jobject byteBuffer;
- PublicFormat readerPublicFormat = static_cast<PublicFormat>(readerFormat);
- int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
- readerPublicFormat);
-
- ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
-
- if (isFormatOpaque(readerHalFormat)) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Opaque images from Opaque ImageReader do not have any plane");
- return NULL;
- }
-
- CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
-
- if (buffer == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
- }
-
- // Create byteBuffer from native buffer
- Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerHalFormat);
-
- if (size > static_cast<uint32_t>(INT32_MAX)) {
- // Byte buffer have 'int capacity', so check the range
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "Size too large for bytebuffer capacity %" PRIu32, size);
- return NULL;
- }
-
- byteBuffer = env->NewDirectByteBuffer(base, size);
- // TODO: throw dvm exOutOfMemoryError?
- if ((byteBuffer == NULL) && (env->ExceptionCheck() == false)) {
- jniThrowException(env, "java/lang/IllegalStateException", "Failed to allocate ByteBuffer");
- }
-
- return byteBuffer;
+ BufferItem* buffer = Image_getBufferItem(env, thiz);
+ return getBufferWidth(buffer);
}
-static jint Image_getWidth(JNIEnv* env, jobject thiz, jint format)
+static jint Image_getHeight(JNIEnv* env, jobject thiz)
{
- if (isFormatOpaque(format)) {
- BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, thiz);
- return Image_getOpaqueBufferWidth(opaqueBuffer);
- } else {
- CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
- return Image_getBufferWidth(buffer);
- }
-}
-
-static jint Image_getHeight(JNIEnv* env, jobject thiz, jint format)
-{
- if (isFormatOpaque(format)) {
- BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, thiz);
- return Image_getOpaqueBufferHeight(opaqueBuffer);
- } else {
- CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
- return Image_getBufferHeight(buffer);
- }
+ BufferItem* buffer = Image_getBufferItem(env, thiz);
+ return getBufferHeight(buffer);
}
static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat)
@@ -1260,20 +742,21 @@
// Assuming opaque reader produce opaque images.
return static_cast<jint>(PublicFormat::PRIVATE);
} else {
- CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+ BufferItem* buffer = Image_getBufferItem(env, thiz);
int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
static_cast<PublicFormat>(readerFormat));
- int32_t fmt = applyFormatOverrides(buffer->flexFormat, readerHalFormat);
+ int32_t fmt = applyFormatOverrides(
+ buffer->mGraphicBuffer->getPixelFormat(), readerHalFormat);
// Override the image format to HAL_PIXEL_FORMAT_YCbCr_420_888 if the actual format is
// NV21 or YV12. This could only happen when the Gralloc HAL version is v0.1 thus doesn't
// support lockycbcr(), the CpuConsumer need to use the lock() method in the
// lockNextBuffer() call. For Gralloc HAL v0.2 or newer, this format should already be
// overridden to HAL_PIXEL_FORMAT_YCbCr_420_888 for the flexible YUV compatible formats.
- if (fmt == HAL_PIXEL_FORMAT_YCrCb_420_SP || fmt == HAL_PIXEL_FORMAT_YV12) {
+ if (isPossiblyYUV(fmt)) {
fmt = HAL_PIXEL_FORMAT_YCbCr_420_888;
}
PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
- fmt, buffer->dataSpace);
+ fmt, buffer->mDataSpace);
return static_cast<jint>(publicFmt);
}
}
@@ -1293,11 +776,10 @@
};
static const JNINativeMethod gImageMethods[] = {
- {"nativeImageGetBuffer", "(II)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer },
- {"nativeCreatePlane", "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
- (void*)Image_createSurfacePlane },
- {"nativeGetWidth", "(I)I", (void*)Image_getWidth },
- {"nativeGetHeight", "(I)I", (void*)Image_getHeight },
+ {"nativeCreatePlanes", "(II)[Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
+ (void*)Image_createSurfacePlanes },
+ {"nativeGetWidth", "()I", (void*)Image_getWidth },
+ {"nativeGetHeight", "()I", (void*)Image_getHeight },
{"nativeGetFormat", "(I)I", (void*)Image_getFormat },
};
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index f50da85..d5d9fc9 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -16,34 +16,28 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ImageWriter_JNI"
+#include "android_media_Utils.h"
+
#include <utils/Log.h>
#include <utils/String8.h>
#include <gui/IProducerListener.h>
#include <gui/Surface.h>
-#include <gui/CpuConsumer.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <camera3.h>
-
#include <jni.h>
#include <JNIHelp.h>
#include <stdint.h>
#include <inttypes.h>
-#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
-
#define IMAGE_BUFFER_JNI_ID "mNativeBuffer"
// ----------------------------------------------------------------------------
using namespace android;
-enum {
- IMAGE_WRITER_MAX_NUM_PLANES = 3,
-};
-
static struct {
jmethodID postEventFromNative;
jfieldID mWriterFormat;
@@ -60,8 +54,6 @@
jmethodID ctor;
} gSurfacePlaneClassInfo;
-typedef CpuConsumer::LockedBuffer LockedImage;
-
// ----------------------------------------------------------------------------
class JNIImageWriterContext : public BnProducerListener {
@@ -181,13 +173,11 @@
// -------------------------------Private method declarations--------------
-static bool isPossiblyYUV(PixelFormat format);
static void Image_setNativeContext(JNIEnv* env, jobject thiz,
sp<GraphicBuffer> buffer, int fenceFd);
static void Image_getNativeContext(JNIEnv* env, jobject thiz,
GraphicBuffer** buffer, int* fenceFd);
static void Image_unlockIfLocked(JNIEnv* env, jobject thiz);
-static bool isFormatOpaque(int format);
// --------------------------ImageWriter methods---------------------------------------
@@ -672,28 +662,6 @@
return buffer->getHeight();
}
-// Some formats like JPEG defined with different values between android.graphics.ImageFormat and
-// graphics.h, need convert to the one defined in graphics.h here.
-static int Image_getPixelFormat(JNIEnv* env, int format) {
- int jpegFormat;
- jfieldID fid;
-
- ALOGV("%s: format = 0x%x", __FUNCTION__, format);
-
- jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat");
- ALOG_ASSERT(imageFormatClazz != NULL);
-
- fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I");
- jpegFormat = env->GetStaticIntField(imageFormatClazz, fid);
-
- // Translate the JPEG to BLOB for camera purpose.
- if (format == jpegFormat) {
- format = HAL_PIXEL_FORMAT_BLOB;
- }
-
- return format;
-}
-
static jint Image_getFormat(JNIEnv* env, jobject thiz) {
ALOGV("%s", __FUNCTION__);
GraphicBuffer* buffer;
@@ -704,7 +672,10 @@
return 0;
}
- return Image_getPixelFormat(env, buffer->getPixelFormat());
+ // ImageWriter doesn't support data space yet, assuming it is unknown.
+ PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
+ buffer->getPixelFormat(), HAL_DATASPACE_UNKNOWN);
+ return static_cast<jint>(publicFmt);
}
static void Image_setFenceFd(JNIEnv* env, jobject thiz, int fenceFd) {
@@ -723,272 +694,34 @@
return;
}
- void* pData = NULL;
- android_ycbcr ycbcr = android_ycbcr();
- status_t res;
- int format = Image_getFormat(env, thiz);
- int flexFormat = format;
- if (isPossiblyYUV(format)) {
- // ImageWriter doesn't use crop by itself, app sets it, use the no crop version.
- res = buffer->lockAsyncYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr, fenceFd);
- // Clear the fenceFd as it is already consumed by lock call.
- Image_setFenceFd(env, thiz, /*fenceFd*/-1);
- if (res != OK) {
- jniThrowRuntimeException(env, "lockAsyncYCbCr failed for YUV buffer");
- return;
- }
- pData = ycbcr.y;
- flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
+ // ImageWriter doesn't use crop by itself, app sets it, use the no crop version.
+ const Rect noCrop(buffer->width, buffer->height);
+ status_t res = lockImageFromBuffer(
+ buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, noCrop, fenceFd, image);
+ // Clear the fenceFd as it is already consumed by lock call.
+ Image_setFenceFd(env, thiz, /*fenceFd*/-1);
+ if (res != OK) {
+ jniThrowExceptionFmt(env, "java/lang/RuntimeException",
+ "lock buffer failed for format 0x%x",
+ buffer->getPixelFormat());
+ return;
}
- // lockAsyncYCbCr for YUV is unsuccessful.
- if (pData == NULL) {
- res = buffer->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, &pData, fenceFd);
- if (res != OK) {
- jniThrowRuntimeException(env, "lockAsync failed");
- return;
- }
- }
-
- image->data = reinterpret_cast<uint8_t*>(pData);
- image->width = buffer->getWidth();
- image->height = buffer->getHeight();
- image->format = format;
- image->flexFormat = flexFormat;
- image->stride = (ycbcr.y != NULL) ? static_cast<uint32_t>(ycbcr.ystride) : buffer->getStride();
-
- image->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
- image->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
- image->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
- image->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
- ALOGV("Successfully locked the image");
+ ALOGV("%s: Successfully locked the image", __FUNCTION__);
// crop, transform, scalingMode, timestamp, and frameNumber should be set by producer,
// and we don't set them here.
}
-static bool usingRGBAToJpegOverride(int32_t bufferFormat, int32_t writerCtxFormat) {
- return writerCtxFormat == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888;
-}
-
-static int32_t applyFormatOverrides(int32_t bufferFormat, int32_t writerCtxFormat)
-{
- // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
- // write limitations for some platforms (b/17379185).
- if (usingRGBAToJpegOverride(bufferFormat, writerCtxFormat)) {
- return HAL_PIXEL_FORMAT_BLOB;
- }
- return bufferFormat;
-}
-
-static uint32_t Image_getJpegSize(LockedImage* buffer, bool usingRGBAOverride) {
- ALOGV("%s", __FUNCTION__);
- ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
- uint32_t size = 0;
- uint32_t width = buffer->width;
- uint8_t* jpegBuffer = buffer->data;
-
- if (usingRGBAOverride) {
- width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
- }
-
- // First check for JPEG transport header at the end of the buffer
- uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
- struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
- if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
- size = blob->jpeg_size;
- ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
- }
-
- // failed to find size, default to whole buffer
- if (size == 0) {
- /*
- * This is a problem because not including the JPEG header
- * means that in certain rare situations a regular JPEG blob
- * will be misidentified as having a header, in which case
- * we will get a garbage size value.
- */
- ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
- __FUNCTION__, width);
- size = width;
- }
-
- return size;
-}
-
static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
ALOGV("%s", __FUNCTION__);
- ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
- ALOG_ASSERT(base != NULL, "base is NULL!!!");
- ALOG_ASSERT(size != NULL, "size is NULL!!!");
- ALOG_ASSERT(pixelStride != NULL, "pixelStride is NULL!!!");
- ALOG_ASSERT(rowStride != NULL, "rowStride is NULL!!!");
- ALOG_ASSERT((idx < IMAGE_WRITER_MAX_NUM_PLANES) && (idx >= 0));
- ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
-
- uint32_t dataSize, ySize, cSize, cStride;
- uint32_t pStride = 0, rStride = 0;
- uint8_t *cb, *cr;
- uint8_t *pData = NULL;
- int bytesPerPixel = 0;
-
- dataSize = ySize = cSize = cStride = 0;
- int32_t fmt = buffer->flexFormat;
-
- bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, writerFormat);
- fmt = applyFormatOverrides(fmt, writerFormat);
- switch (fmt) {
- case HAL_PIXEL_FORMAT_YCbCr_420_888:
- pData =
- (idx == 0) ?
- buffer->data :
- (idx == 1) ?
- buffer->dataCb :
- buffer->dataCr;
- // only map until last pixel
- if (idx == 0) {
- pStride = 1;
- rStride = buffer->stride;
- dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
- } else {
- pStride = buffer->chromaStep;
- rStride = buffer->chromaStride;
- dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
- buffer->chromaStep * (buffer->width / 2 - 1) + 1;
- }
- break;
- // NV21
- case HAL_PIXEL_FORMAT_YCrCb_420_SP:
- cr = buffer->data + (buffer->stride * buffer->height);
- cb = cr + 1;
- // only map until last pixel
- ySize = buffer->width * (buffer->height - 1) + buffer->width;
- cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
-
- pData =
- (idx == 0) ?
- buffer->data :
- (idx == 1) ?
- cb:
- cr;
-
- dataSize = (idx == 0) ? ySize : cSize;
- pStride = (idx == 0) ? 1 : 2;
- rStride = buffer->width;
- break;
- case HAL_PIXEL_FORMAT_YV12:
- // Y and C stride need to be 16 pixel aligned.
- LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
- "Stride is not 16 pixel aligned %d", buffer->stride);
-
- ySize = buffer->stride * buffer->height;
- cStride = ALIGN(buffer->stride / 2, 16);
- cr = buffer->data + ySize;
- cSize = cStride * buffer->height / 2;
- cb = cr + cSize;
-
- pData =
- (idx == 0) ?
- buffer->data :
- (idx == 1) ?
- cb :
- cr;
- dataSize = (idx == 0) ? ySize : cSize;
- pStride = 1;
- rStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
- break;
- case HAL_PIXEL_FORMAT_Y8:
- // Single plane, 8bpp.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height;
- pStride = 1;
- rStride = buffer->stride;
- break;
- case HAL_PIXEL_FORMAT_Y16:
- bytesPerPixel = 2;
- // Single plane, 16bpp, strides are specified in pixels, not in bytes
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
-
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- pStride = bytesPerPixel;
- rStride = buffer->stride * 2;
- break;
- case HAL_PIXEL_FORMAT_BLOB:
- // Used for JPEG data, height must be 1, width == size, single plane.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height);
-
- pData = buffer->data;
- dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
- pStride = bytesPerPixel;
- rowStride = 0;
- break;
- case HAL_PIXEL_FORMAT_RAW16:
- // Single plane 16bpp bayer data.
- bytesPerPixel = 2;
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- pStride = bytesPerPixel;
- rStride = buffer->stride * 2;
- break;
- case HAL_PIXEL_FORMAT_RAW10:
- // Single plane 10bpp bayer data.
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- LOG_ALWAYS_FATAL_IF(buffer->width % 4,
- "Width is not multiple of 4 %d", buffer->width);
- LOG_ALWAYS_FATAL_IF(buffer->height % 2,
- "Height is not even %d", buffer->height);
- LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
- "stride (%d) should be at least %d",
- buffer->stride, buffer->width * 10 / 8);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height;
- pStride = 0;
- rStride = buffer->stride;
- break;
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- // Single plane, 32bpp.
- bytesPerPixel = 4;
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- pStride = bytesPerPixel;
- rStride = buffer->stride * 4;
- break;
- case HAL_PIXEL_FORMAT_RGB_565:
- // Single plane, 16bpp.
- bytesPerPixel = 2;
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- pStride = bytesPerPixel;
- rStride = buffer->stride * 2;
- break;
- case HAL_PIXEL_FORMAT_RGB_888:
- // Single plane, 24bpp.
- bytesPerPixel = 3;
- ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
- pData = buffer->data;
- dataSize = buffer->stride * buffer->height * bytesPerPixel;
- pStride = bytesPerPixel;
- rStride = buffer->stride * 3;
- break;
- default:
- jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
- "Pixel format: 0x%x is unsupported", fmt);
- break;
+ status_t res = getLockedImageInfo(buffer, idx, writerFormat, base, size,
+ pixelStride, rowStride);
+ if (res != OK) {
+ jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
+ "Pixel format: 0x%x is unsupported", buffer->flexFormat);
}
-
- *base = pData;
- *size = dataSize;
- *pixelStride = pStride;
- *rowStride = rStride;
}
static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
@@ -1024,7 +757,8 @@
Image_getLockedImage(env, thiz, &lockedImg);
// Create all SurfacePlanes
- writerFormat = Image_getPixelFormat(env, writerFormat);
+ PublicFormat publicWriterFormat = static_cast<PublicFormat>(writerFormat);
+ writerFormat = android_view_Surface_mapPublicFormatToHalFormat(publicWriterFormat);
for (int i = 0; i < numPlanes; i++) {
Image_getLockedImageInfo(env, &lockedImg, i, writerFormat,
&pData, &dataSize, &pixelStride, &rowStride);
@@ -1044,39 +778,6 @@
return surfacePlanes;
}
-// -------------------------------Private convenience methods--------------------
-
-static bool isFormatOpaque(int format) {
- // Only treat IMPLEMENTATION_DEFINED as an opaque format for now.
- return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-}
-
-static bool isPossiblyYUV(PixelFormat format) {
- switch (static_cast<int>(format)) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- case HAL_PIXEL_FORMAT_RGB_888:
- case HAL_PIXEL_FORMAT_RGB_565:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- case HAL_PIXEL_FORMAT_Y8:
- case HAL_PIXEL_FORMAT_Y16:
- case HAL_PIXEL_FORMAT_RAW16:
- case HAL_PIXEL_FORMAT_RAW10:
- case HAL_PIXEL_FORMAT_RAW_OPAQUE:
- case HAL_PIXEL_FORMAT_BLOB:
- case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
- return false;
-
- case HAL_PIXEL_FORMAT_YV12:
- case HAL_PIXEL_FORMAT_YCbCr_420_888:
- case HAL_PIXEL_FORMAT_YCbCr_422_SP:
- case HAL_PIXEL_FORMAT_YCrCb_420_SP:
- case HAL_PIXEL_FORMAT_YCbCr_422_I:
- default:
- return true;
- }
-}
-
} // extern "C"
// ----------------------------------------------------------------------------
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 9c4f7c4..527e6c2 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -26,32 +26,82 @@
#include <nativehelper/ScopedLocalRef.h>
+#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
+
namespace android {
+AssetStream::AssetStream(SkStream* stream)
+ : mStream(stream) {
+}
+
+AssetStream::~AssetStream() {
+}
+
+piex::Error AssetStream::GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) {
+ // Seek first.
+ if (mPosition != offset) {
+ if (!mStream->seek(offset)) {
+ return piex::Error::kFail;
+ }
+ }
+
+ // Read bytes.
+ size_t size = mStream->read((void*)data, length);
+ mPosition += size;
+
+ return size == length ? piex::Error::kOk : piex::Error::kFail;
+}
+
+BufferedStream::BufferedStream(SkStream* stream)
+ : mStream(stream) {
+}
+
+BufferedStream::~BufferedStream() {
+}
+
+piex::Error BufferedStream::GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) {
+ // Seek first.
+ if (offset + length > mStreamBuffer.bytesWritten()) {
+ size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten();
+ if (sizeToRead <= kMinSizeToRead) {
+ sizeToRead = kMinSizeToRead;
+ }
+ void* tempBuffer = malloc(sizeToRead);
+ if (tempBuffer != NULL) {
+ size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
+ if (bytesRead != sizeToRead) {
+ free(tempBuffer);
+ return piex::Error::kFail;
+ }
+ mStreamBuffer.write(tempBuffer, bytesRead);
+ free(tempBuffer);
+ }
+ }
+
+ // Read bytes.
+ if (mStreamBuffer.read((void*)data, offset, length)) {
+ return piex::Error::kOk;
+ } else {
+ return piex::Error::kFail;
+ }
+}
+
FileStream::FileStream(const int fd)
- : mPosition(0),
- mSize(0) {
+ : mPosition(0) {
mFile = fdopen(fd, "r");
if (mFile == NULL) {
return;
}
- // Get the size.
- fseek(mFile, 0l, SEEK_END);
- mSize = ftell(mFile);
- fseek(mFile, 0l, SEEK_SET);
}
FileStream::FileStream(const String8 filename)
- : mPosition(0),
- mSize(0) {
+ : mPosition(0) {
mFile = fopen(filename.string(), "r");
if (mFile == NULL) {
return;
}
- // Get the size.
- fseek(mFile, 0l, SEEK_END);
- mSize = ftell(mFile);
- fseek(mFile, 0l, SEEK_SET);
}
FileStream::~FileStream() {
@@ -77,7 +127,7 @@
mPosition += size;
// Handle errors.
- if (ferror(mFile) || (size == 0 && feof(mFile))) {
+ if (ferror(mFile)) {
ALOGV("GetData read failed: (offset: %zu, length: %zu)", offset, length);
return piex::Error::kFail;
}
@@ -88,21 +138,12 @@
return mFile != NULL;
}
-size_t FileStream::size() const {
- return mSize;
-}
-
bool GetExifFromRawImage(
- FileStream* stream, const String8& filename, piex::PreviewImageData& image_data) {
+ piex::StreamInterface* stream, const String8& filename,
+ piex::PreviewImageData& image_data) {
// Reset the PreviewImageData to its default.
image_data = piex::PreviewImageData();
- if (!stream->exists()) {
- // File is not exists.
- ALOGV("File is not exists: %s", filename.string());
- return false;
- }
-
if (!piex::IsRaw(stream)) {
// Format not supported.
ALOGV("Format not supported: %s", filename.string());
@@ -117,12 +158,6 @@
return false;
}
- if (image_data.thumbnail_offset + image_data.thumbnail_length > stream->size()) {
- // Corrupted image.
- ALOGV("Corrupted file: %s", filename.string());
- return false;
- }
-
return true;
}
@@ -509,5 +544,391 @@
return OK;
}
+// -----------Utility functions used by ImageReader/Writer JNI-----------------
+
+enum {
+ IMAGE_MAX_NUM_PLANES = 3,
+};
+
+bool usingRGBAToJpegOverride(int32_t imageFormat,
+ int32_t containerFormat) {
+ return containerFormat == HAL_PIXEL_FORMAT_BLOB && imageFormat == HAL_PIXEL_FORMAT_RGBA_8888;
+}
+
+int32_t applyFormatOverrides(int32_t imageFormat, int32_t containerFormat) {
+ // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
+ // write limitations for some platforms (b/17379185).
+ if (usingRGBAToJpegOverride(imageFormat, containerFormat)) {
+ return HAL_PIXEL_FORMAT_BLOB;
+ }
+ return containerFormat;
+}
+
+bool isFormatOpaque(int format) {
+ // This is the only opaque format exposed in the ImageFormat public API.
+ // Note that we do support CPU access for HAL_PIXEL_FORMAT_RAW_OPAQUE
+ // (ImageFormat#RAW_PRIVATE) so it doesn't count as opaque here.
+ return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+}
+
+bool isPossiblyYUV(PixelFormat format) {
+ switch (static_cast<int>(format)) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_RGB_888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_Y8:
+ case HAL_PIXEL_FORMAT_Y16:
+ case HAL_PIXEL_FORMAT_RAW16:
+ case HAL_PIXEL_FORMAT_RAW10:
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+ case HAL_PIXEL_FORMAT_BLOB:
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ return false;
+
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ default:
+ return true;
+ }
+}
+
+uint32_t Image_getJpegSize(LockedImage* buffer, bool usingRGBAOverride) {
+ ALOGV("%s", __FUNCTION__);
+ LOG_ALWAYS_FATAL_IF(buffer == NULL, "Input buffer is NULL!!!");
+ uint32_t size = 0;
+ uint32_t width = buffer->width;
+ uint8_t* jpegBuffer = buffer->data;
+
+ if (usingRGBAOverride) {
+ width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
+ }
+
+ // First check for JPEG transport header at the end of the buffer
+ uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
+ struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
+ if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
+ size = blob->jpeg_size;
+ ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
+ }
+
+ // failed to find size, default to whole buffer
+ if (size == 0) {
+ /*
+ * This is a problem because not including the JPEG header
+ * means that in certain rare situations a regular JPEG blob
+ * will be mis-identified as having a header, in which case
+ * we will get a garbage size value.
+ */
+ ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
+ __FUNCTION__, width);
+ size = width;
+ }
+
+ return size;
+}
+
+status_t getLockedImageInfo(LockedImage* buffer, int idx,
+ int32_t containerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
+ ALOGV("%s", __FUNCTION__);
+ LOG_ALWAYS_FATAL_IF(buffer == NULL, "Input buffer is NULL!!!");
+ LOG_ALWAYS_FATAL_IF(base == NULL, "base is NULL!!!");
+ LOG_ALWAYS_FATAL_IF(size == NULL, "size is NULL!!!");
+ LOG_ALWAYS_FATAL_IF(pixelStride == NULL, "pixelStride is NULL!!!");
+ LOG_ALWAYS_FATAL_IF(rowStride == NULL, "rowStride is NULL!!!");
+ LOG_ALWAYS_FATAL_IF((idx >= IMAGE_MAX_NUM_PLANES) || (idx < 0), "idx (%d) is illegal", idx);
+
+ ALOGV("%s: buffer: %p", __FUNCTION__, buffer);
+
+ uint32_t dataSize, ySize, cSize, cStride;
+ uint32_t pStride = 0, rStride = 0;
+ uint8_t *cb, *cr;
+ uint8_t *pData = NULL;
+ int bytesPerPixel = 0;
+
+ dataSize = ySize = cSize = cStride = 0;
+ int32_t fmt = buffer->flexFormat;
+
+ bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, containerFormat);
+ fmt = applyFormatOverrides(fmt, containerFormat);
+ switch (fmt) {
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ pData =
+ (idx == 0) ?
+ buffer->data :
+ (idx == 1) ?
+ buffer->dataCb :
+ buffer->dataCr;
+ // only map until last pixel
+ if (idx == 0) {
+ pStride = 1;
+ rStride = buffer->stride;
+ dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
+ } else {
+ pStride = buffer->chromaStep;
+ rStride = buffer->chromaStride;
+ dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
+ buffer->chromaStep * (buffer->width / 2 - 1) + 1;
+ }
+ break;
+ // NV21
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ cr = buffer->data + (buffer->stride * buffer->height);
+ cb = cr + 1;
+ // only map until last pixel
+ ySize = buffer->width * (buffer->height - 1) + buffer->width;
+ cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;
+
+ pData =
+ (idx == 0) ?
+ buffer->data :
+ (idx == 1) ?
+ cb:
+ cr;
+
+ dataSize = (idx == 0) ? ySize : cSize;
+ pStride = (idx == 0) ? 1 : 2;
+ rStride = buffer->width;
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ // Y and C stride need to be 16 pixel aligned.
+ LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
+ "Stride is not 16 pixel aligned %d", buffer->stride);
+
+ ySize = buffer->stride * buffer->height;
+ cStride = ALIGN(buffer->stride / 2, 16);
+ cr = buffer->data + ySize;
+ cSize = cStride * buffer->height / 2;
+ cb = cr + cSize;
+
+ pData =
+ (idx == 0) ?
+ buffer->data :
+ (idx == 1) ?
+ cb :
+ cr;
+ dataSize = (idx == 0) ? ySize : cSize;
+ pStride = 1;
+ rStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
+ break;
+ case HAL_PIXEL_FORMAT_Y8:
+ // Single plane, 8bpp.
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+
+ pData = buffer->data;
+ dataSize = buffer->stride * buffer->height;
+ pStride = 1;
+ rStride = buffer->stride;
+ break;
+ case HAL_PIXEL_FORMAT_Y16:
+ bytesPerPixel = 2;
+ // Single plane, 16bpp, strides are specified in pixels, not in bytes
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+
+ pData = buffer->data;
+ dataSize = buffer->stride * buffer->height * bytesPerPixel;
+ pStride = bytesPerPixel;
+ rStride = buffer->stride * 2;
+ break;
+ case HAL_PIXEL_FORMAT_BLOB:
+ // Used for JPEG data, height must be 1, width == size, single plane.
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+ LOG_ALWAYS_FATAL_IF(buffer->height != 1,
+ "BLOB format buffer should has height value %d", buffer->height);
+
+ pData = buffer->data;
+ dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
+ pStride = 0;
+ rStride = 0;
+ break;
+ case HAL_PIXEL_FORMAT_RAW16:
+ // Single plane 16bpp bayer data.
+ bytesPerPixel = 2;
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+ pData = buffer->data;
+ dataSize = buffer->stride * buffer->height * bytesPerPixel;
+ pStride = bytesPerPixel;
+ rStride = buffer->stride * 2;
+ break;
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+ // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+ LOG_ALWAYS_FATAL_IF(buffer->height != 1,
+ "RAW_PRIVATE should has height value one but got %d", buffer->height);
+ pData = buffer->data;
+ dataSize = buffer->width;
+ pStride = 0; // RAW OPAQUE doesn't have pixel stride
+ rStride = 0; // RAW OPAQUE doesn't have row stride
+ break;
+ case HAL_PIXEL_FORMAT_RAW10:
+ // Single plane 10bpp bayer data.
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+ LOG_ALWAYS_FATAL_IF(buffer->width % 4,
+ "Width is not multiple of 4 %d", buffer->width);
+ LOG_ALWAYS_FATAL_IF(buffer->height % 2,
+ "Height is not even %d", buffer->height);
+ LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
+ "stride (%d) should be at least %d",
+ buffer->stride, buffer->width * 10 / 8);
+ pData = buffer->data;
+ dataSize = buffer->stride * buffer->height;
+ pStride = 0;
+ rStride = buffer->stride;
+ break;
+ case HAL_PIXEL_FORMAT_RAW12:
+ // Single plane 10bpp bayer data.
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+ LOG_ALWAYS_FATAL_IF(buffer->width % 4,
+ "Width is not multiple of 4 %d", buffer->width);
+ LOG_ALWAYS_FATAL_IF(buffer->height % 2,
+ "Height is not even %d", buffer->height);
+ LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 12 / 8),
+ "stride (%d) should be at least %d",
+ buffer->stride, buffer->width * 12 / 8);
+ pData = buffer->data;
+ dataSize = buffer->stride * buffer->height;
+ pStride = 0;
+ rStride = buffer->stride;
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ // Single plane, 32bpp.
+ bytesPerPixel = 4;
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+ pData = buffer->data;
+ dataSize = buffer->stride * buffer->height * bytesPerPixel;
+ pStride = bytesPerPixel;
+ rStride = buffer->stride * 4;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ // Single plane, 16bpp.
+ bytesPerPixel = 2;
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+ pData = buffer->data;
+ dataSize = buffer->stride * buffer->height * bytesPerPixel;
+ pStride = bytesPerPixel;
+ rStride = buffer->stride * 2;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ // Single plane, 24bpp.
+ bytesPerPixel = 3;
+ LOG_ALWAYS_FATAL_IF(idx != 0, "Wrong index: %d", idx);
+ pData = buffer->data;
+ dataSize = buffer->stride * buffer->height * bytesPerPixel;
+ pStride = bytesPerPixel;
+ rStride = buffer->stride * 3;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ *base = pData;
+ *size = dataSize;
+ *pixelStride = pStride;
+ *rowStride = rStride;
+
+ return OK;
+}
+
+status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage,
+ const Rect& rect, int fenceFd, LockedImage* outputImage) {
+ ALOGV("%s: Try to lock the GraphicBuffer", __FUNCTION__);
+
+ if (buffer == nullptr || outputImage == nullptr) {
+ ALOGE("Input BufferItem or output LockedImage is NULL!");
+ return BAD_VALUE;
+ }
+ if (isFormatOpaque(buffer->getPixelFormat())) {
+ ALOGE("Opaque format buffer is not lockable!");
+ return BAD_VALUE;
+ }
+
+ void* pData = NULL;
+ android_ycbcr ycbcr = android_ycbcr();
+ status_t res;
+ int format = buffer->getPixelFormat();
+ int flexFormat = format;
+ if (isPossiblyYUV(format)) {
+ res = buffer->lockAsyncYCbCr(inUsage, rect, &ycbcr, fenceFd);
+ pData = ycbcr.y;
+ flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
+ }
+
+ // lockAsyncYCbCr for YUV is unsuccessful.
+ if (pData == NULL) {
+ res = buffer->lockAsync(inUsage, rect, &pData, fenceFd);
+ if (res != OK) {
+ ALOGE("Lock buffer failed!");
+ return res;
+ }
+ }
+
+ outputImage->data = reinterpret_cast<uint8_t*>(pData);
+ outputImage->width = buffer->getWidth();
+ outputImage->height = buffer->getHeight();
+ outputImage->format = format;
+ outputImage->flexFormat = flexFormat;
+ outputImage->stride =
+ (ycbcr.y != NULL) ? static_cast<uint32_t>(ycbcr.ystride) : buffer->getStride();
+
+ outputImage->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
+ outputImage->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
+ outputImage->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
+ outputImage->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
+ ALOGV("%s: Successfully locked the image from the GraphicBuffer", __FUNCTION__);
+ // Crop, transform, scalingMode, timestamp, and frameNumber should be set by caller,
+ // and cann't be set them here.
+ return OK;
+}
+
+status_t lockImageFromBuffer(BufferItem* bufferItem, uint32_t inUsage,
+ int fenceFd, LockedImage* outputImage) {
+ ALOGV("%s: Try to lock the BufferItem", __FUNCTION__);
+ if (bufferItem == nullptr || outputImage == nullptr) {
+ ALOGE("Input BufferItem or output LockedImage is NULL!");
+ return BAD_VALUE;
+ }
+
+ status_t res = lockImageFromBuffer(bufferItem->mGraphicBuffer, inUsage, bufferItem->mCrop,
+ fenceFd, outputImage);
+ if (res != OK) {
+ ALOGE("%s: lock graphic buffer failed", __FUNCTION__);
+ return res;
+ }
+
+ outputImage->crop = bufferItem->mCrop;
+ outputImage->transform = bufferItem->mTransform;
+ outputImage->scalingMode = bufferItem->mScalingMode;
+ outputImage->timestamp = bufferItem->mTimestamp;
+ outputImage->dataSpace = bufferItem->mDataSpace;
+ outputImage->frameNumber = bufferItem->mFrameNumber;
+ ALOGV("%s: Successfully locked the image from the BufferItem", __FUNCTION__);
+ return OK;
+}
+
+int getBufferWidth(BufferItem* buffer) {
+ if (buffer == NULL) return -1;
+
+ if (!buffer->mCrop.isEmpty()) {
+ return buffer->mCrop.getWidth();
+ }
+
+ ALOGV("%s: buffer->mGraphicBuffer: %p", __FUNCTION__, buffer->mGraphicBuffer.get());
+ return buffer->mGraphicBuffer->getWidth();
+}
+
+int getBufferHeight(BufferItem* buffer) {
+ if (buffer == NULL) return -1;
+
+ if (!buffer->mCrop.isEmpty()) {
+ return buffer->mCrop.getHeight();
+ }
+
+ ALOGV("%s: buffer->mGraphicBuffer: %p", __FUNCTION__, buffer->mGraphicBuffer.get());
+ return buffer->mGraphicBuffer->getHeight();
+}
+
} // namespace android
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
index a30e1be..8184f94 100644
--- a/media/jni/android_media_Utils.h
+++ b/media/jni/android_media_Utils.h
@@ -21,18 +21,62 @@
#include "src/piex.h"
#include <android_runtime/AndroidRuntime.h>
+#include <camera3.h>
+#include <gui/CpuConsumer.h>
#include <jni.h>
#include <JNIHelp.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
+#include <SkStream.h>
namespace android {
+class AssetStream : public piex::StreamInterface {
+private:
+ SkStream *mStream;
+ size_t mPosition;
+
+public:
+ AssetStream(SkStream* stream);
+ ~AssetStream();
+
+ // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
+ // provided by the caller, guaranteed to be at least "length" bytes long.
+ // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
+ // 'offset' bytes from the start of the stream.
+ // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
+ // change the contents of 'data'.
+ piex::Error GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) override;
+};
+
+class BufferedStream : public piex::StreamInterface {
+private:
+ SkStream *mStream;
+ // Growable memory stream
+ SkDynamicMemoryWStream mStreamBuffer;
+
+ // Minimum size to read on filling the buffer.
+ const size_t kMinSizeToRead = 8192;
+
+public:
+ BufferedStream(SkStream* stream);
+ ~BufferedStream();
+
+ // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
+ // provided by the caller, guaranteed to be at least "length" bytes long.
+ // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
+ // 'offset' bytes from the start of the stream.
+ // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
+ // change the contents of 'data'.
+ piex::Error GetData(
+ const size_t offset, const size_t length, std::uint8_t* data) override;
+};
+
class FileStream : public piex::StreamInterface {
private:
FILE *mFile;
size_t mPosition;
- size_t mSize;
public:
FileStream(const int fd);
@@ -48,13 +92,12 @@
piex::Error GetData(
const size_t offset, const size_t length, std::uint8_t* data) override;
bool exists() const;
- size_t size() const;
};
// Reads EXIF metadata from a given raw image via piex.
// And returns true if the operation is successful; otherwise, false.
bool GetExifFromRawImage(
- FileStream* stream, const String8& filename, piex::PreviewImageData& image_data);
+ piex::StreamInterface* stream, const String8& filename, piex::PreviewImageData& image_data);
// Returns true if the conversion is successful; otherwise, false.
bool ConvertKeyValueArraysToKeyedVector(
@@ -69,6 +112,33 @@
JNIEnv *env, jobjectArray keys, jobjectArray values,
sp<AMessage> *msg);
+// -----------Utility functions used by ImageReader/Writer JNI-----------------
+
+typedef CpuConsumer::LockedBuffer LockedImage;
+
+bool usingRGBAToJpegOverride(int32_t imageFormat, int32_t containerFormat);
+
+int32_t applyFormatOverrides(int32_t imageFormat, int32_t containerFormat);
+
+uint32_t Image_getJpegSize(LockedImage* buffer, bool usingRGBAOverride);
+
+bool isFormatOpaque(int format);
+
+bool isPossiblyYUV(PixelFormat format);
+
+status_t getLockedImageInfo(LockedImage* buffer, int idx, int32_t containerFormat,
+ uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride);
+
+status_t lockImageFromBuffer(sp<GraphicBuffer> buffer, uint32_t inUsage,
+ const Rect& rect, int fenceFd, LockedImage* outputImage);
+
+status_t lockImageFromBuffer(BufferItem* bufferItem, uint32_t inUsage,
+ int fenceFd, LockedImage* outputImage);
+
+int getBufferWidth(BufferItem *buffer);
+
+int getBufferHeight(BufferItem *buffer);
+
}; // namespace android
#endif // _ANDROID_MEDIA_UTILS_H_
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 7c1142b..7e438a1 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -11,7 +11,6 @@
LOCAL_STATIC_JAVA_LIBRARIES := easymocklib \
mockito-target \
- core-tests \
android-support-test \
android-ex-camera2
diff --git a/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_ii.jpg b/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_ii.jpg
new file mode 100644
index 0000000..477cd3a
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_ii.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_mm.jpg b/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_mm.jpg
new file mode 100644
index 0000000..78ac703
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/assets/image_exif_byte_order_mm.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/assets/lg_g4_iso_800.dng b/media/tests/MediaFrameworkTest/assets/lg_g4_iso_800.dng
new file mode 100644
index 0000000..5fcc720
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/assets/lg_g4_iso_800.dng
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/assets/volantis.jpg b/media/tests/MediaFrameworkTest/assets/volantis.jpg
new file mode 100644
index 0000000..cfe300f
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/assets/volantis.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/raw/volantis.jpg b/media/tests/MediaFrameworkTest/res/raw/volantis.jpg
new file mode 100644
index 0000000..cfe300f
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/raw/volantis.jpg
Binary files differ
diff --git a/media/tests/MediaFrameworkTest/res/values/exifinterface.xml b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
index 8fc6adc..d556ad3 100644
--- a/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
+++ b/media/tests/MediaFrameworkTest/res/values/exifinterface.xml
@@ -76,9 +76,9 @@
<item>0</item>
</array>
<array name="lg_g4_iso_800_dng">
- <item>false</item>
- <item>0</item>
- <item>0</item>
+ <item>true</item>
+ <item>256</item>
+ <item>144</item>
<item>true</item>
<item>53.834507</item>
<item>10.69585</item>
@@ -105,4 +105,34 @@
<item>1</item>
<item />
</array>
+ <array name="volantis_jpg">
+ <item>false</item>
+ <item>0</item>
+ <item>0</item>
+ <item>true</item>
+ <item>37.423</item>
+ <item>-122.162</item>
+ <item>0.0</item>
+ <item>htc</item>
+ <item>Nexus 9</item>
+ <item>1.2904</item>
+ <item>2016:03:09 17:36:42</item>
+ <item>0.0083</item>
+ <item>64</item>
+ <item>3097/1000</item>
+ <item />
+ <item />
+ <item>2016:03:09</item>
+ <item>37/1,25/1,2291/100</item>
+ <item>N</item>
+ <item>122/1,9/1,4330/100</item>
+ <item>W</item>
+ <item />
+ <item>08:35:34</item>
+ <item>720</item>
+ <item>1280</item>
+ <item>175</item>
+ <item>1</item>
+ <item>0</item>
+ </array>
</resources>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
index 1c80746..5bd6079 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -23,20 +23,20 @@
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.os.Environment;
-import android.os.ParcelFileDescriptor;
import android.test.AndroidTestCase;
import android.util.Log;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
-import java.lang.reflect.Type;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -46,16 +46,17 @@
private static final boolean VERBOSE = false; // lots of logging
private static final double DIFFERENCE_TOLERANCE = .005;
- private static final int BUFFER_SIZE = 32768;
// List of files.
- private static final String EXIF_BYTE_ORDER_II_JPEG = "ExifByteOrderII.jpg";
- private static final String EXIF_BYTE_ORDER_MM_JPEG = "ExifByteOrderMM.jpg";
+ private static final String EXIF_BYTE_ORDER_II_JPEG = "image_exif_byte_order_ii.jpg";
+ private static final String EXIF_BYTE_ORDER_MM_JPEG = "image_exif_byte_order_mm.jpg";
private static final String LG_G4_ISO_800_DNG = "lg_g4_iso_800.dng";
+ private static final String VOLANTIS_JPEG = "volantis.jpg";
private static final int[] IMAGE_RESOURCES = new int[] {
- R.raw.image_exif_byte_order_ii, R.raw.image_exif_byte_order_mm, R.raw.lg_g4_iso_800 };
+ R.raw.image_exif_byte_order_ii, R.raw.image_exif_byte_order_mm, R.raw.lg_g4_iso_800,
+ R.raw.volantis };
private static final String[] IMAGE_FILENAMES = new String[] {
- EXIF_BYTE_ORDER_II_JPEG, EXIF_BYTE_ORDER_MM_JPEG, LG_G4_ISO_800_DNG };
+ EXIF_BYTE_ORDER_II_JPEG, EXIF_BYTE_ORDER_MM_JPEG, LG_G4_ISO_800_DNG, VOLANTIS_JPEG };
private static final String[] EXIF_TAGS = {
ExifInterface.TAG_MAKE,
@@ -165,8 +166,6 @@
@Override
protected void setUp() throws Exception {
- byte[] buffer = new byte[BUFFER_SIZE];
-
for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
String outputPath = new File(Environment.getExternalStorageDirectory(),
IMAGE_FILENAMES[i]).getAbsolutePath();
@@ -314,26 +313,30 @@
expectedValue.whiteBalance);
}
- private void testExifInterfaceForJpeg(String fileName, int typedArrayResourceId)
+ private void testExifInterfaceCommon(File imageFile, ExpectedValue expectedValue)
throws IOException {
- ExpectedValue expectedValue = new ExpectedValue(
- getContext().getResources().obtainTypedArray(typedArrayResourceId));
- File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
-
// Created via path.
ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
if (VERBOSE) {
- printExifTagsAndValues(fileName, exifInterface);
+ printExifTagsAndValues(imageFile.getName(), exifInterface);
+ }
+ compareWithExpectedValue(exifInterface, expectedValue);
+
+ // Created from an asset file.
+ InputStream in = mContext.getAssets().open(imageFile.getName());
+ exifInterface = new ExifInterface(in);
+ if (VERBOSE) {
+ printExifTagsAndValues(imageFile.getName(), exifInterface);
}
compareWithExpectedValue(exifInterface, expectedValue);
// Created via InputStream.
- FileInputStream in = null;
+ in = null;
try {
- in = new FileInputStream(imageFile.getAbsolutePath());
+ in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
exifInterface = new ExifInterface(in);
if (VERBOSE) {
- printExifTagsAndValues(fileName, exifInterface);
+ printExifTagsAndValues(imageFile.getName(), exifInterface);
}
compareWithExpectedValue(exifInterface, expectedValue);
} finally {
@@ -345,18 +348,30 @@
FileDescriptor fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
exifInterface = new ExifInterface(fd);
if (VERBOSE) {
- printExifTagsAndValues(fileName, exifInterface);
+ printExifTagsAndValues(imageFile.getName(), exifInterface);
}
compareWithExpectedValue(exifInterface, expectedValue);
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
+ }
+
+ private void testExifInterfaceForJpeg(String fileName, int typedArrayResourceId)
+ throws IOException {
+ ExpectedValue expectedValue = new ExpectedValue(
+ getContext().getResources().obtainTypedArray(typedArrayResourceId));
+ File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+
+ // Test for reading from various inputs.
+ testExifInterfaceCommon(imageFile, expectedValue);
// Test for saving attributes.
+ ExifInterface exifInterface;
try {
FileDescriptor fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
exifInterface = new ExifInterface(fd);
exifInterface.saveAttributes();
+ fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDWR, 0600);
exifInterface = new ExifInterface(fd);
if (VERBOSE) {
printExifTagsAndValues(fileName, exifInterface);
@@ -383,25 +398,11 @@
getContext().getResources().obtainTypedArray(typedArrayResourceId));
File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
- // Created via path.
- ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
- if (VERBOSE) {
- printExifTagsAndValues(fileName, exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
+ // Test for reading from various inputs.
+ testExifInterfaceCommon(imageFile, expectedValue);
- // Created via FileDescriptor.
- FileInputStream in = null;
- try {
- in = new FileInputStream(imageFile);
- exifInterface = new ExifInterface(in.getFD());
- if (VERBOSE) {
- printExifTagsAndValues(fileName, exifInterface);
- }
- compareWithExpectedValue(exifInterface, expectedValue);
- } finally {
- IoUtils.closeQuietly(in);
- }
+ // Since ExifInterface does not support for saving attributes for RAW files, do not test
+ // about writing back in here.
}
public void testReadExifDataFromExifByteOrderIIJpeg() throws Throwable {
@@ -415,4 +416,19 @@
public void testReadExifDataFromLgG4Iso800Dng() throws Throwable {
testExifInterfaceForRaw(LG_G4_ISO_800_DNG, R.array.lg_g4_iso_800_dng);
}
+
+ public void testCorruptedImage() throws Throwable {
+ byte[] bytes = new byte[1024];
+ try {
+ new ExifInterface(new ByteArrayInputStream(bytes));
+ fail("Should not reach here!");
+ } catch (IOException e) {
+ // Success
+ }
+ }
+
+ public void testReadExifDataFromVolantisJpg() throws Throwable {
+ // Test if it is possible to parse the volantis generated JPEG smoothly.
+ testExifInterfaceForJpeg(VOLANTIS_JPEG, R.array.volantis_jpg);
+ }
}
diff --git a/packages/DocumentsUI/res/color/item_details.xml b/packages/DocumentsUI/res/color/item_details.xml
new file mode 100644
index 0000000..769b944
--- /dev/null
+++ b/packages/DocumentsUI/res/color/item_details.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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_enabled="true"
+ android:color="?android:attr/textColorPrimary"
+ android:alpha="0.63" />
+ <item
+ android:state_enabled="false"
+ android:color="?android:attr/textColorPrimary"
+ android:alpha="0.3" />
+</selector>
diff --git a/packages/DocumentsUI/res/color/item_title.xml b/packages/DocumentsUI/res/color/item_title.xml
new file mode 100644
index 0000000..ef6aea3
--- /dev/null
+++ b/packages/DocumentsUI/res/color/item_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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_enabled="true"
+ android:color="?android:attr/textColorPrimary" />
+ <item
+ android:state_enabled="false"
+ android:color="?android:attr/textColorPrimary"
+ android:alpha="0.3" />
+</selector>
diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml
index a4f06d1..429a972 100644
--- a/packages/DocumentsUI/res/layout/item_dir_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml
@@ -66,7 +66,7 @@
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
- android:textColor="@*android:color/primary_text_default_material_light" />
+ android:textColor="@color/item_title" />
</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index af1703f..56a061f 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -93,7 +93,7 @@
android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
- android:textColor="@*android:color/primary_text_default_material_light" />
+ android:textColor="@color/item_title" />
<TextView
android:id="@+id/size"
@@ -106,7 +106,7 @@
android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Caption"
- android:textColor="@*android:color/primary_text_default_material_light" />
+ android:textColor="@color/item_details" />
<TextView
android:id="@+id/date"
@@ -118,7 +118,7 @@
android:ellipsize="end"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Caption"
- android:textColor="@*android:color/primary_text_default_material_light" />
+ android:textColor="@color/item_details" />
</RelativeLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index 29f65e09..a939fcd 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -85,7 +85,7 @@
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
- android:textColor="?android:attr/textColorPrimary" />
+ android:textColor="@color/item_title" />
<LinearLayout
android:id="@+id/line2"
@@ -102,8 +102,8 @@
android:ellipsize="end"
android:singleLine="true"
android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:textAppearance="@android:style/TextAppearance.Material.Caption"
+ android:textColor="@color/item_details" />
<TextView
android:id="@+id/size"
@@ -113,8 +113,8 @@
android:ellipsize="end"
android:singleLine="true"
android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:textAppearance="@android:style/TextAppearance.Material.Caption"
+ android:textColor="@color/item_details" />
<TextView
android:id="@android:id/summary"
@@ -125,8 +125,8 @@
android:ellipsize="end"
android:singleLine="true"
android:textAlignment="viewStart"
- android:textAppearance="@android:style/TextAppearance.Material.Body1"
- android:textColor="?android:attr/textColorSecondary" />
+ android:textAppearance="@android:style/TextAppearance.Material.Caption"
+ android:textColor="@color/item_details" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 79f6fa9..2aee569 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -66,7 +66,7 @@
android:id="@+id/menu_sort"
android:title="@string/menu_sort"
android:icon="@drawable/ic_menu_sortby"
- android:showAsAction="never">
+ android:showAsAction="ifRoom">
<menu>
<item
android:id="@+id/menu_sort_name"
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index d195ed5..f01c81d 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Vee <xliff:g id="COUNT_1">%1$d</xliff:g> lêers uit?</item>
<item quantity="one">Vee <xliff:g id="COUNT_0">%1$d</xliff:g> lêer uit?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index d04980e..c61db57 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -116,4 +116,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች ይሰረዙ?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 157d07f..817f226 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -148,4 +148,5 @@
<item quantity="other">هل تريد حذف <xliff:g id="COUNT_1">%1$d</xliff:g> ملف؟</item>
<item quantity="one">هل تريد حذف <xliff:g id="COUNT_0">%1$d</xliff:g> ملف؟</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index 2e07260..2e6f04c 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> fayl silinsin?</item>
<item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> fayl silinsin?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 457c3e7..36e24834 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -124,4 +124,5 @@
<item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
<item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index c0fb178..74d18f8 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Искате ли да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
<item quantity="one">Искате ли да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> файл?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 0c5e4cb..0e3c552 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল মুছবেন?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index 03387c3..ea8214e 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -124,4 +124,5 @@
<item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla.</item>
<item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova.</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 42eab75..8a35368 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers?</item>
<item quantity="one">Vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index a9b6724..001a84b 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -132,4 +132,5 @@
<item quantity="other">Smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souborů?</item>
<item quantity="one">Smazat <xliff:g id="COUNT_0">%1$d</xliff:g> soubor?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 661e81f..a72cf02 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
<item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index ebbbf31..ed589e0 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Möchtest du <xliff:g id="COUNT_1">%1$d</xliff:g> Dateien löschen?</item>
<item quantity="one">Möchtest du <xliff:g id="COUNT_0">%1$d</xliff:g> Datei löschen?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 39e6828..7a9d597 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Να διαγραφούν <xliff:g id="COUNT_1">%1$d</xliff:g> αρχεία;</item>
<item quantity="one">Να διαγραφεί <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείο;</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index c18f1a5..8b46660 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
<item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index c18f1a5..8b46660 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
<item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index c18f1a5..8b46660 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">Delete <xliff:g id="COUNT_1">%1$d</xliff:g> files?</item>
<item quantity="one">Delete <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selected</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selected</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 2808e5f..9d525af 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">¿Deseas borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
<item quantity="one">¿Deseas borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index c8dae74..81fc59abb 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">¿Eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
<item quantity="one">¿Eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> seleccionados</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seleccionado</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 5574954..7cf134e 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">Kas kustutada <xliff:g id="COUNT_1">%1$d</xliff:g> faili?</item>
<item quantity="one">Kas kustutada <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> on valitud</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> on valitud</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 0dc1cf8..2576709 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi ezabatu nahi dituzu?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi ezabatu nahi duzu?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 52d4910f..312f207 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فایل حذف شود؟</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 6afbef2..0cb4de2 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Poistetaanko <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa?</item>
<item quantity="one">Poistetaanko <xliff:g id="COUNT_0">%1$d</xliff:g> tiedosto?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 2ec6773..73f1bda 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier?</item>
<item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 531a4ee..b32696f 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier ?</item>
<item quantity="other">Supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers ?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index 3d7bdc2..d9bf7e3 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
<item quantity="one">Queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 4559354..a1aa3d4 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલ કાઢી નાખીએ?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index b00b5f8..489bb98 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -116,4 +116,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें हटाएं?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index c413e5f..51b8673 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -124,4 +124,9 @@
<item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
<item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="one">Odabrano: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="few">Odabrano: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="other">Odabrano: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index c3dca3e..b7e74e0 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">Töröl <xliff:g id="COUNT_1">%1$d</xliff:g> fájlt?</item>
<item quantity="one">Töröl <xliff:g id="COUNT_0">%1$d</xliff:g> fájlt?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> kiválasztva</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kiválasztva</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index f811928..c7a14c1 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
<item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index ecf668c..73ed8bc 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">Hapus <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
<item quantity="one">Hapus <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dipilih</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index 5606d8f..1b9ff9a 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrá?</item>
<item quantity="other">Eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrám?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index 959f33a..c9329ad 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
<item quantity="one">Eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 3c57e8a..7d4cb9e9 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -132,4 +132,10 @@
<item quantity="other">האם למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
<item quantity="one">האם למחוק קובץ <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="two"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
+ <item quantity="many"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> נבחרו</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> נבחר</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index fbfa5ed..a79ecc5 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを削除しますか?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを削除しますか?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index ea3633c..7824910 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის წაშლა?</item>
<item quantity="one">გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> ფაილის წაშლა?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index 1618e13..5537af7 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды жою керек пе?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файлды жою керек пе?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 3934348..1e1b3f8 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">លុបឯកសារ <xliff:g id="COUNT_1">%1$d</xliff:g> ច្បាប់ឬ?</item>
<item quantity="one">លុបឯកសារ <xliff:g id="COUNT_0">%1$d</xliff:g> ច្បាប់ឬ?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 0dda6f1..83bed30 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
<item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್ಗಳನ್ನು ಅಳಿಸುವುದೇ?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index bb6c6530d..e313925 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">파일 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
<item quantity="one">파일 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 삭제하시겠습니까?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index ec5faf8..6b8395a 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл жок кылынсынбы?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл жок кылынсынбы?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index b896835..468853b 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">ລຶບ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
<item quantity="one">ລຶບ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟລ໌ອອກບໍ?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other">ເລືອກ <xliff:g id="COUNT_1">%1$d</xliff:g> ແລ້ວ</item>
+ <item quantity="one">ເລືອກ <xliff:g id="COUNT_0">%1$d</xliff:g> ແລ້ວ</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 71fe331..91f5948 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -132,4 +132,5 @@
<item quantity="many">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failo?</item>
<item quantity="other">Ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failų?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index d974573..d3154d1 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -124,4 +124,5 @@
<item quantity="one">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failu?</item>
<item quantity="other">Vai izdzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 632a510..f7486f1 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -114,6 +114,7 @@
<string name="deny" msgid="2081879885755434506">"Одбиј"</string>
<plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
<item quantity="one">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
- <item quantity="other">Да се избрише <xliff:g id="COUNT_1">%1$d</xliff:g> датотеки?</item>
+ <item quantity="other">Да се избришат <xliff:g id="COUNT_1">%1$d</xliff:g> датотеки?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index 5441e0c..e164ad2 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ ഇല്ലാതാക്കണോ?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫയൽ ഇല്ലാതാക്കണോ?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index b556188..fae1f04 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлыг устгах уу?</item>
<item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> файлыг устгах уу?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index 721f2d2..0def32f 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> फाईल हटवायची?</item>
<item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> फायली हटवायच्या?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 9985eb6..ef62ec4 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Padamkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail?</item>
<item quantity="one">Padamkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 3e581ae..08bdfc1 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">ဖိုင် <xliff:g id="COUNT_1">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
<item quantity="one">ဖိုင် <xliff:g id="COUNT_0">%1$d</xliff:g> ခုကိုဖျက်မလား။</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 8257d4a..3326a55 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Vil du slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
<item quantity="one">Vil du slette <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index 2320192..191574c 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फाइलहरूलाई मेट्ने हो?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> फाइललाई मेट्ने हो?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 17b6031..ebddf54 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> bestanden verwijderen?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> bestand verwijderen?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> geselecteerd</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> geselecteerd</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 009acbea..a8c65e7 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -116,4 +116,8 @@
<item quantity="one">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
<item quantity="other">ਕੀ <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣੀ ਗਈ</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣੀਆਂ ਗਈਆਂ</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index b9bec5d..60dbda8 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -132,4 +132,5 @@
<item quantity="other">Usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliku?</item>
<item quantity="one">Usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> plik?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index 158bd1d..92939ba1 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
<item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index 14c6291..2c74e67 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">Pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
<item quantity="one">Pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selecionado</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 158bd1d..92939ba1 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
<item quantity="other">Excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 241be4e..eda2eac 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -124,4 +124,5 @@
<item quantity="other">Ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere?</item>
<item quantity="one">Ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> fișier?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 606c1c5..5719fe8 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -132,4 +132,5 @@
<item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов?</item>
<item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index a818bae..7c2e3a2 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g>ක් මකන්නද?</item>
<item quantity="other">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g>ක් මකන්නද?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index d8b1970..818c276 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -132,4 +132,5 @@
<item quantity="other">Odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súborov?</item>
<item quantity="one">Odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> súbor?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index c7ab185..1994f07 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -132,4 +132,5 @@
<item quantity="few">Želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
<item quantity="other">Želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> datotek?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index be87dc2..671b5ea 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Të fshihen <xliff:g id="COUNT_1">%1$d</xliff:g> skedarë?</item>
<item quantity="one">Të fshihet <xliff:g id="COUNT_0">%1$d</xliff:g> skedar?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index ae6b11b..de45e61 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -124,4 +124,5 @@
<item quantity="few">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке?</item>
<item quantity="other">Желите ли да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 1e7eb60..7fd4be0 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other">Radera <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
<item quantity="one">Radera <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> har valts</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> har valts</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index b3f0a6d..ce042f0 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Ungependa kufuta faili <xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
<item quantity="one">Ungependa kufuta faili <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/config.xml b/packages/DocumentsUI/res/values-sw720dp-land/config.xml
index 8d9526d..6893d7a 100644
--- a/packages/DocumentsUI/res/values-sw720dp-land/config.xml
+++ b/packages/DocumentsUI/res/values-sw720dp-land/config.xml
@@ -15,5 +15,4 @@
-->
<resources>
- <bool name="always_show_summary">true</bool>
</resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 7c19e53..5bd71ae 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நீக்கவா?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நீக்கவா?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index d12bbb8..0043ddc 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -116,4 +116,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్లను తొలగించాలా?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఫైల్ను తొలగించాలా?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఎంచుకోబడ్డాయి</item>
+ <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఎంచుకోబడింది</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 678628c..fbc170e 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">ลบ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
<item quantity="one">ลบ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์ใช่ไหม</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 9079c55..8a4f148 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
<item quantity="other">Gusto mo bang i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index a462491..ceb5c48 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya silinsin mi?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya silinsin mi?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 2fc411e..d5a1fcd 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -132,4 +132,10 @@
<item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлів?</item>
<item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлу?</item>
</plurals>
+ <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
+ <item quantity="one">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="few">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="many">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ <item quantity="other">Вибрано <xliff:g id="COUNT_1">%1$d</xliff:g></item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 733d312..b96a96f 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں حذف کریں؟</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل حذف کریں؟</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index 20da8d0..72cc7d9 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl o‘chirilsinmi?</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayl o‘chirilsinmi?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index c7df892..adb3ffe 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">Xóa <xliff:g id="COUNT_1">%1$d</xliff:g> tệp?</item>
<item quantity="one">Xóa <xliff:g id="COUNT_0">%1$d</xliff:g> tệp?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 15deb7b..ccf5d42 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -113,7 +113,8 @@
<string name="allow" msgid="7225948811296386551">"允许"</string>
<string name="deny" msgid="2081879885755434506">"拒绝"</string>
<plurals name="delete_confirmation_message" formatted="false" msgid="3519107568984207772">
- <item quantity="other">要删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件吗?</item>
- <item quantity="one">要删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件吗?</item>
+ <item quantity="other">删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件?</item>
+ <item quantity="one">删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index dd95df5..ecd0071 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
<item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 41ed922..ea83ab2 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -116,4 +116,5 @@
<item quantity="other">要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
<item quantity="one">要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index cc90163..4588b12 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -116,4 +116,5 @@
<item quantity="one">Sula amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
<item quantity="other">Sula amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
</plurals>
+ <!-- no translation found for elements_selected (1376955402452875047) -->
</resources>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 3785adf..04b7fee 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -23,8 +23,6 @@
<color name="window_background">#fff1f1f1</color>
<color name="drawer_background">#fff1f1f1</color>
<color name="directory_background">#fff7f7f7</color>
- <color name="item_doc_background">#fffafafa</color>
- <color name="item_doc_background_selected">#ffe0f2f1</color>
<color name="menu_search_background">#ff676f74</color>
<color name="primary_dark">@*android:color/primary_dark_material_dark</color>
@@ -35,4 +33,11 @@
<color name="band_select_background">#88ffffff</color>
<color name="band_select_border">#44000000</color>
+
+ <color name="item_doc_background_disabled">#fff4f4f4</color>
+
+ <!-- TODO: Would be nice to move this to a color-set, but not sure how to support animation -->
+ <color name="item_doc_background">#fffafafa</color>
+ <color name="item_doc_background_selected">#ffe0f2f1</color>
+
</resources>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index 8a76540..86087c3 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -21,5 +21,4 @@
<!-- Intentionally unset. Vendors should set this in an overlay. -->
<string name="trusted_quick_viewer_package" translatable="false"></string>
<bool name="list_divider_inset_left">true</bool>
- <bool name="always_show_summary">false</bool>
</resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 6e1b30e..e2d1870 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -213,4 +213,9 @@
<item quantity="one">Delete <xliff:g id="count" example="1">%1$d</xliff:g> file?</item>
<item quantity="other">Delete <xliff:g id="count" example="3">%1$d</xliff:g> files?</item>
</plurals>
+ <!-- Label text showing user how many items are selected. Can be one or more elements. -->
+ <plurals name="elements_selected">
+ <item quantity="one"><xliff:g id="count" example="1">%1$d</xliff:g> selected</item>
+ <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
+ </plurals>
</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 6efe9d1..c9d18b3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -154,7 +154,7 @@
final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
// Search uses backend ranking; no sorting, recents doesn't support sort.
- sort.setVisible(!inRecents && !mSearchManager.isSearching());
+ sort.setEnabled(!inRecents && !mSearchManager.isSearching());
sortSize.setVisible(mState.showSize); // Only sort by size when file sizes are visible
fileSize.setVisible(!mState.forceSize);
@@ -244,6 +244,7 @@
return true;
case R.id.menu_search:
+ // SearchViewManager listens for this directly.
return false;
case R.id.menu_sort_name:
@@ -366,6 +367,7 @@
assert(canSearchRoot());
reloadSearch(query);
+ invalidateOptionsMenu();
}
private void reloadSearch(String query) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index a77a9b3..8fcd9d1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -113,8 +113,8 @@
}
private int collectViewableUris(ArrayList<Uri> uris) {
- final List<String> siblingIds = mModel.getModelIds();
- uris.ensureCapacity(siblingIds.size());
+ final String[] siblingIds = mModel.getModelIds();
+ uris.ensureCapacity(siblingIds.length);
int documentLocation = 0;
Cursor cursor;
@@ -124,8 +124,8 @@
Uri uri;
// Cursor's are not guaranteed to be immutable. Hence, traverse it only once.
- for (int i = 0; i < siblingIds.size(); i++) {
- cursor = mModel.getItem(siblingIds.get(i));
+ for (int i = 0; i < siblingIds.length; i++) {
+ cursor = mModel.getItem(siblingIds[i]);
mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 1967923..ca1b444 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -63,6 +63,7 @@
import android.view.ActionMode;
import android.view.DragEvent;
import android.view.GestureDetector;
+import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -526,7 +527,8 @@
getActivity().getWindow().setStatusBarColor(color.data);
if (mActionMode != null) {
- mActionMode.setTitle(String.valueOf(mSelected.size()));
+ mActionMode.setTitle(Shared.getQuantityString(getActivity(),
+ R.plurals.elements_selected, mSelected.size()));
}
}
@@ -544,6 +546,8 @@
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ mRecView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+
int size = mSelectionManager.getSelection().size();
mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
mode.setTitle(TextUtils.formatSelectedCount(size));
@@ -586,18 +590,17 @@
case R.id.menu_share:
shareDocuments(selection);
- mode.finish();
return true;
case R.id.menu_delete:
- // Exit selection mode first, so we avoid deselecting deleted documents.
- mode.finish();
- deleteDocuments(selection);
+ // Pass mode along to the delete function so it can
+ // end action mode when documents are deleted.
+ // It won't end action mode if user cancels the delete.
+ deleteDocuments(selection, mode);
return true;
case R.id.menu_copy_to:
transferDocuments(selection, FileOperationService.OPERATION_COPY);
- mode.finish();
return true;
case R.id.menu_move_to:
@@ -615,8 +618,10 @@
return true;
case R.id.menu_rename:
- renameDocuments(selection);
+ // Exit selection mode first, so we avoid deselecting deleted
+ // (renamed) documents.
mode.finish();
+ renameDocuments(selection);
return true;
default:
@@ -700,7 +705,7 @@
}.execute(selected);
}
- private void deleteDocuments(final Selection selected) {
+ private void deleteDocuments(final Selection selected, final ActionMode mode) {
assert(!selected.isEmpty());
final DocumentInfo srcParent = getDisplayState().stack.peek();
@@ -732,7 +737,15 @@
android.R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- // Hide the files in the UI.
+ // Finish selection mode first which clears selection so we
+ // don't end up trying to deselect deleted documents.
+ // This is done here, rather in the onActionItemClicked
+ // so we can avoid de-selecting items in the case where
+ // the user cancels the delete.
+ mode.finish();
+ // Hide the files in the UI...since the operation
+ // might be queued up on FileOperationService.
+ // We're walking a line here.
mAdapter.hide(selected.getAll());
FileOperations.delete(
getActivity(), docs, srcParent, getDisplayState().stack);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
index 3b5ce87..5edda38 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -16,6 +16,7 @@
package com.android.documentsui.dirlist;
+import android.annotation.ColorInt;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Rect;
@@ -35,17 +36,19 @@
extends RecyclerView.ViewHolder
implements View.OnKeyListener {
+ static final float DISABLED_ALPHA = 0.3f;
+
public @Nullable String modelId;
- final int mSelectedItemColor;
- final int mDefaultItemColor;
- final boolean mAlwaysShowSummary;
final Context mContext;
+ final @ColorInt int mDefaultBgColor;
+ final @ColorInt int mSelectedBgColor;
DocumentHolder.EventListener mEventListener;
private View.OnKeyListener mKeyListener;
private View mSelectionHotspot;
+
public DocumentHolder(Context context, ViewGroup parent, int layout) {
this(context, inflateLayout(context, parent, layout));
}
@@ -57,9 +60,8 @@
mContext = context;
- mDefaultItemColor = context.getColor(R.color.item_doc_background);
- mSelectedItemColor = context.getColor(R.color.item_doc_background_selected);
- mAlwaysShowSummary = context.getResources().getBoolean(R.bool.always_show_summary);
+ mDefaultBgColor = context.getColor(R.color.item_doc_background);
+ mSelectedBgColor = context.getColor(R.color.item_doc_background_selected);
mSelectionHotspot = itemView.findViewById(R.id.icon_check);
}
@@ -80,7 +82,7 @@
*/
public void setSelected(boolean selected) {
itemView.setActivated(selected);
- itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
+ itemView.setBackgroundColor(selected ? mSelectedBgColor : mDefaultBgColor);
}
/**
@@ -88,7 +90,11 @@
* @param highlighted
*/
public void setHighlighted(boolean highlighted) {
- itemView.setBackgroundColor(highlighted ? mSelectedItemColor : mDefaultItemColor);
+ itemView.setBackgroundColor(highlighted ? mSelectedBgColor : mDefaultBgColor);
+ }
+
+ public void setEnabled(boolean enabled) {
+ setEnabledRecursive(itemView, enabled);
}
@Override
@@ -111,10 +117,6 @@
mKeyListener = listener;
}
- public void setEnabled(boolean enabled) {
- setEnabledRecursive(itemView, enabled);
- }
-
public boolean onSingleTapUp(MotionEvent event) {
if (Events.isMouseEvent(event)) {
// Mouse clicks select.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
index a4bce16..e7fa28b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -20,6 +20,7 @@
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import android.annotation.ColorInt;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
@@ -37,6 +38,7 @@
import com.android.documentsui.State;
final class GridDocumentHolder extends DocumentHolder {
+
private static boolean mHideTitles;
final TextView mTitle;
@@ -48,9 +50,13 @@
final ImageView mIconCheck;
final IconHelper mIconHelper;
+ private final @ColorInt int mDisabledBgColor;
+
public GridDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) {
super(context, parent, R.layout.item_doc_grid);
+ mDisabledBgColor = context.getColor(R.color.item_doc_background_disabled);
+
mTitle = (TextView) itemView.findViewById(android.R.id.title);
mDate = (TextView) itemView.findViewById(R.id.date);
mSize = (TextView) itemView.findViewById(R.id.size);
@@ -64,13 +70,35 @@
@Override
public void setSelected(boolean selected) {
- super.setSelected(selected);
+ // We always want to make sure our check box disappears if we're not selected,
+ // even if the item is disabled. This is because this object can be reused
+ // and this method will be called to setup initial state.
float checkAlpha = selected ? 1f : 0f;
-
mIconCheck.animate().alpha(checkAlpha).start();
+
+ // But it should be an error to be set to selected && be disabled.
+ if (!itemView.isEnabled()) {
+ assert(!selected);
+ return;
+ }
+
+ super.setSelected(selected);
+
mIconMimeSm.animate().alpha(1f - checkAlpha).start();
}
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+
+ // Text colors enabled/disabled is handle via a color set.
+ itemView.setBackgroundColor(enabled ? mDefaultBgColor : mDisabledBgColor);
+ float imgAlpha = enabled ? 1f : DISABLED_ALPHA;
+
+ mIconMimeLg.setAlpha(imgAlpha);
+ mIconMimeSm.setAlpha(imgAlpha);
+ mIconThumb.setAlpha(imgAlpha);
+ }
+
/**
* Bind this view to the given document for display.
* @param cursor Pointing to the item to be bound.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
index 0831dbf..3a1be11 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -66,14 +66,33 @@
@Override
public void setSelected(boolean selected) {
- super.setSelected(selected);
+ // We always want to make sure our check box disappears if we're not selected,
+ // even if the item is disabled. But it should be an error (see assert below)
+ // to be set to selected && be disabled.
float checkAlpha = selected ? 1f : 0f;
-
mIconCheck.animate().alpha(checkAlpha).start();
+
+ if (!itemView.isEnabled()) {
+ assert(!selected);
+ return;
+ }
+
+ super.setSelected(selected);
+
mIconMime.animate().alpha(1f - checkAlpha).start();
mIconThumb.animate().alpha(1f - checkAlpha).start();
}
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+
+ // Text colors enabled/disabled is handle via a color set.
+ final float imgAlpha = enabled ? 1f : DISABLED_ALPHA;
+ mIconMime.setAlpha(imgAlpha);
+ mIconThumb.setAlpha(imgAlpha);
+ }
+
/**
* Bind this view to the given document for display.
* @param cursor Pointing to the item to be bound.
@@ -145,12 +164,4 @@
mDetails.setVisibility(hasDetails ? View.VISIBLE : View.GONE);
}
}
-
- @Override
- public void setEnabled(boolean enabled) {
- super.setEnabled(enabled);
- final float iconAlpha = enabled ? 1f : 0.5f;
- mIconMime.setAlpha(iconAlpha);
- mIconThumb.setAlpha(iconAlpha);
- }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index 8170e2a..ab4f5c4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -59,7 +59,7 @@
* A sorted array of model IDs for the files currently in the Model. Sort order is determined
* by {@link #mSortOrder}
*/
- private List<String> mIds = new ArrayList<>();
+ private String mIds[] = new String[0];
private int mSortOrder = SORT_ORDER_DISPLAY_NAME;
@Nullable String info;
@@ -108,7 +108,7 @@
if (result == null) {
mCursor = null;
mCursorCount = 0;
- mIds.clear();
+ mIds = new String[0];
mPositions.clear();
info = null;
error = null;
@@ -152,7 +152,7 @@
*/
private void updateModelData() {
int[] positions = new int[mCursorCount];
- mIds.clear();
+ mIds = new String[mCursorCount];
String[] stringValues = new String[mCursorCount];
long[] longValues = null;
@@ -164,7 +164,7 @@
for (int pos = 0; pos < mCursorCount; ++pos) {
mCursor.moveToNext();
positions[pos] = pos;
- mIds.add(createModelId(mCursor));
+ mIds[pos] = createModelId(mCursor);
switch(mSortOrder) {
case SORT_ORDER_DISPLAY_NAME:
@@ -201,7 +201,7 @@
// Populate the positions.
mPositions.clear();
for (int i = 0; i < mCursorCount; ++i) {
- mPositions.put(mIds.get(i), positions[i]);
+ mPositions.put(mIds[i], positions[i]);
}
}
@@ -214,12 +214,12 @@
* @param positions Cursor positions to be sorted.
* @param ids Model IDs to be sorted.
*/
- private static void binarySort(String[] sortKey, int[] positions, List<String> ids) {
+ private static void binarySort(String[] sortKey, int[] positions, String[] ids) {
final int count = positions.length;
for (int start = 1; start < count; start++) {
final int pivotPosition = positions[start];
final String pivotValue = sortKey[start];
- final String pivotId = ids.get(start);
+ final String pivotId = ids[start];
int left = 0;
int right = start;
@@ -243,23 +243,21 @@
case 2:
positions[left + 2] = positions[left + 1];
sortKey[left + 2] = sortKey[left + 1];
- ids.set(left + 2, ids.get(left + 1));
+ ids[left + 2] = ids[left + 1];
case 1:
positions[left + 1] = positions[left];
sortKey[left + 1] = sortKey[left];
- ids.set(left + 1, ids.get(left));
+ ids[left + 1] = ids[left];
break;
default:
System.arraycopy(positions, left, positions, left + 1, n);
System.arraycopy(sortKey, left, sortKey, left + 1, n);
- for (int i = n; i >= 1; --i) {
- ids.set(left + i, ids.get(left + i - 1));
- }
+ System.arraycopy(ids, left, ids, left + 1, n);
}
positions[left] = pivotPosition;
sortKey[left] = pivotValue;
- ids.set(left, pivotId);
+ ids[left] = pivotId;
}
}
@@ -275,13 +273,13 @@
* @param ids Model IDs to be sorted.
*/
private static void binarySort(
- long[] sortKey, String[] mimeTypes, int[] positions, List<String> ids) {
+ long[] sortKey, String[] mimeTypes, int[] positions, String[] ids) {
final int count = positions.length;
for (int start = 1; start < count; start++) {
final int pivotPosition = positions[start];
final long pivotValue = sortKey[start];
final String pivotMime = mimeTypes[start];
- final String pivotId = ids.get(start);
+ final String pivotId = ids[start];
int left = 0;
int right = start;
@@ -310,7 +308,7 @@
// have identical numerical sort keys. One common example of this scenario is seen
// when sorting a set of active downloads by mod time.
if (compare == 0) {
- compare = pivotId.compareTo(ids.get(mid));
+ compare = pivotId.compareTo(ids[mid]);
}
if (compare < 0) {
@@ -326,26 +324,24 @@
positions[left + 2] = positions[left + 1];
sortKey[left + 2] = sortKey[left + 1];
mimeTypes[left + 2] = mimeTypes[left + 1];
- ids.set(left + 2, ids.get(left + 1));
+ ids[left + 2] = ids[left + 1];
case 1:
positions[left + 1] = positions[left];
sortKey[left + 1] = sortKey[left];
mimeTypes[left + 1] = mimeTypes[left];
- ids.set(left + 1, ids.get(left));
+ ids[left + 1] = ids[left];
break;
default:
System.arraycopy(positions, left, positions, left + 1, n);
System.arraycopy(sortKey, left, sortKey, left + 1, n);
System.arraycopy(mimeTypes, left, mimeTypes, left + 1, n);
- for (int i = n; i >= 1; --i) {
- ids.set(left + i, ids.get(left + i - 1));
- }
+ System.arraycopy(ids, left, ids, left + 1, n);
}
positions[left] = pivotPosition;
sortKey[left] = pivotValue;
mimeTypes[left] = pivotMime;
- ids.set(left, pivotId);
+ ids[left] = pivotId;
}
}
@@ -413,7 +409,7 @@
* @return An ordered array of model IDs representing the documents in the model. It is sorted
* according to the current sort order, which was set by the last model update.
*/
- public List<String> getModelIds() {
+ public String[] getModelIds() {
return mIds;
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index 2b07339..149ecdd 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -118,8 +118,13 @@
final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+ boolean enabled = mEnv.isDocumentEnabled(docMimeType, docFlags);
+ boolean selected = mEnv.isSelected(modelId);
+ if (!enabled) {
+ assert(!selected);
+ }
+ holder.setEnabled(enabled);
holder.setSelected(mEnv.isSelected(modelId));
- holder.setEnabled(mEnv.isDocumentEnabled(docMimeType, docFlags));
mEnv.onBindDocumentHolder(holder, cursor);
}
@@ -135,8 +140,8 @@
Log.d(TAG, "Updating model with hidden ids: " + mHiddenIds);
}
- List<String> modelIds = model.getModelIds();
- mModelIds = new ArrayList<>(modelIds.size());
+ String[] modelIds = model.getModelIds();
+ mModelIds = new ArrayList<>(modelIds.length);
for (String id : modelIds) {
if (!mHiddenIds.contains(id)) {
mModelIds.add(id);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
index dc39235..f1b4681 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
@@ -68,7 +68,7 @@
@Override
public Notification getProgressNotification() {
- return getProgressNotification(R.string.copy_preparing);
+ return getProgressNotification(R.string.copy_remaining);
}
@Override
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
index 5f33b32..9a06807 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java
@@ -16,9 +16,8 @@
package com.android.documentsui;
-import static com.android.documentsui.StubProvider.ROOT_0_ID;
-
import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
@LargeTest
public class RenameDocumentUiTest extends ActivityTest<FilesActivity> {
@@ -73,6 +72,7 @@
device.pressBack();
}
+ @Suppress
public void testRenameFile_OkButton() throws Exception {
bots.directory.selectDocument(fileName1);
bots.main.openOverflowMenu();
@@ -101,6 +101,7 @@
bots.directory.assertDocumentsCount(4);
}
+ @Suppress
public void testRenameFile_Cancel() throws Exception {
bots.directory.selectDocument(fileName1);
bots.main.openOverflowMenu();
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
index adc8141..7ab51ba2 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
@@ -68,8 +68,8 @@
// Tests that the item count is correct.
public void testHide_ItemCount() {
- List<String> ids = mModel.getModelIds();
- mAdapter.hide(ids.get(0), ids.get(1));
+ String[] ids = mModel.getModelIds();
+ mAdapter.hide(ids[0], ids[1]);
assertEquals(mModel.getItemCount() - 2, mAdapter.getItemCount());
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
index 4b0bc41..c6ad511 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -107,7 +107,7 @@
assertTrue(model.isEmpty());
assertEquals(0, model.getItemCount());
- assertEquals(0, model.getModelIds().size());
+ assertEquals(0, model.getModelIds().length);
}
// Tests that the item count is correct.
@@ -165,10 +165,10 @@
// Tests the base case for Model.getItem.
public void testGetItem() {
- List<String> ids = model.getModelIds();
- assertEquals(ITEM_COUNT, ids.size());
+ String[] ids = model.getModelIds();
+ assertEquals(ITEM_COUNT, ids.length);
for (int i = 0; i < ITEM_COUNT; ++i) {
- Cursor c = model.getItem(ids.get(i));
+ Cursor c = model.getItem(ids[i]);
assertEquals(i, c.getPosition());
}
}
@@ -292,14 +292,14 @@
r.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
model.update(r);
- List<String> ids = model.getModelIds();
+ String[] ids = model.getModelIds();
// Check that all items were accounted for
- assertEquals(ITEM_COUNT + DL_COUNT, ids.size());
+ assertEquals(ITEM_COUNT + DL_COUNT, ids.length);
// Check that active downloads are sorted to the top.
for (int i = 0; i < DL_COUNT; i++) {
- assertTrue(currentDownloads.contains(ids.get(i)));
+ assertTrue(currentDownloads.contains(ids[i]));
}
}
@@ -316,11 +316,11 @@
}
private Selection positionToSelection(int... positions) {
- List<String> ids = model.getModelIds();
+ String[] ids = model.getModelIds();
Selection s = new Selection();
// Construct a selection of the given positions.
for (int p: positions) {
- s.add(ids.get(p));
+ s.add(ids[p]);
}
return s;
}
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index 100b35c..519db66 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -15,18 +15,27 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="android.ext.services"
android:versionCode="1"
android:versionName="1"
coreApp="true">
<application android:label="@string/app_name"
- android:allowBackup="false"
android:forceDeviceEncrypted="true"
android:encryptionAware="true">
<library android:name="android.ext.services"/>
+ <service android:name=".notification.Ranker"
+ android:label="@string/notification_ranker"
+ android:permission="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationRankerService" />
+ </intent-filter>
+ </service>
+
</application>
</manifest>
diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml
index 531e517..0763403 100644
--- a/packages/ExtServices/res/values/strings.xml
+++ b/packages/ExtServices/res/values/strings.xml
@@ -16,4 +16,5 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">Android Services Library</string>
+ <string name="notification_ranker">Android Notification Ranking Service</string>
</resources>
diff --git a/packages/ExtServices/src/android/ext/services/notification/Ranker.java b/packages/ExtServices/src/android/ext/services/notification/Ranker.java
new file mode 100644
index 0000000..0b2b1a4
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/notification/Ranker.java
@@ -0,0 +1,46 @@
+/*
+ * 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.ext.services.notification;
+
+import android.service.notification.NotificationRankerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+/**
+ * Class that provides an updatable ranker module for the notification manager..
+ */
+public final class Ranker extends NotificationRankerService {
+ private static final String TAG = "RocketRanker";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);;
+
+ @Override
+ public Adjustment onNotificationEnqueued(StatusBarNotification sbn, int importance,
+ boolean user) {
+ if (DEBUG) Log.i(TAG, "ENQUEUED " + sbn.getKey());
+ return null;
+ }
+
+ @Override
+ public void onNotificationPosted(StatusBarNotification sbn) {
+ if (DEBUG) Log.i(TAG, "POSTED " + sbn.getKey());
+ }
+
+ @Override
+ public void onListenerConnected() {
+ if (DEBUG) Log.i(TAG, "CONNECTED");
+ }
+}
\ No newline at end of file
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 203d6dc..72ad2f6 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -32,6 +32,7 @@
import android.media.MediaFile;
import android.mtp.MtpConstants;
import android.mtp.MtpObjectInfo;
+import android.net.Uri;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
@@ -40,8 +41,9 @@
import com.android.internal.util.Preconditions;
import java.io.FileNotFoundException;
-import java.io.IOException;
+import java.util.HashSet;
import java.util.Objects;
+import java.util.Set;
/**
* Database for MTP objects.
@@ -606,7 +608,7 @@
* @param deviceId Device to find documents.
* @return Identifier of found document or null.
*/
- public @Nullable Identifier getUnmappedDocumentsParent(int deviceId) {
+ @Nullable Identifier getUnmappedDocumentsParent(int deviceId) {
final String fromClosure =
TABLE_DOCUMENTS + " AS child INNER JOIN " +
TABLE_DOCUMENTS + " AS parent ON " +
@@ -643,6 +645,65 @@
}
}
+ /**
+ * Removes metadata except for data used by outgoingPersistedUriPermissions.
+ */
+ void cleanDatabase(Uri[] outgoingPersistedUris) {
+ mDatabase.beginTransaction();
+ try {
+ final Set<String> ids = new HashSet<>();
+ for (final Uri uri : outgoingPersistedUris) {
+ String documentId = DocumentsContract.getDocumentId(uri);
+ while (documentId != null) {
+ if (ids.contains(documentId)) {
+ break;
+ }
+ ids.add(documentId);
+ try (final Cursor cursor = mDatabase.query(
+ TABLE_DOCUMENTS,
+ strings(COLUMN_PARENT_DOCUMENT_ID),
+ SELECTION_DOCUMENT_ID,
+ strings(documentId),
+ null,
+ null,
+ null)) {
+ documentId = cursor.moveToNext() ? cursor.getString(0) : null;
+ }
+ }
+ }
+ deleteDocumentsAndRoots(
+ Document.COLUMN_DOCUMENT_ID + " NOT IN " + getIdList(ids), null);
+ mDatabase.setTransactionSuccessful();
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
+ int getLastBootCount() {
+ try (final Cursor cursor = mDatabase.query(
+ TABLE_LAST_BOOT_COUNT, strings(COLUMN_VALUE), null, null, null, null, null)) {
+ if (cursor.moveToNext()) {
+ return cursor.getInt(0);
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ void setLastBootCount(int value) {
+ Preconditions.checkArgumentNonnegative(value, "Boot count must not be negative.");
+ mDatabase.beginTransaction();
+ try {
+ final ContentValues values = new ContentValues();
+ values.put(COLUMN_VALUE, value);
+ mDatabase.delete(TABLE_LAST_BOOT_COUNT, null, null);
+ mDatabase.insert(TABLE_LAST_BOOT_COUNT, null, values);
+ mDatabase.setTransactionSuccessful();
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
private static class OpenHelper extends SQLiteOpenHelper {
public OpenHelper(Context context, int flags) {
super(context,
@@ -655,12 +716,14 @@
public void onCreate(SQLiteDatabase db) {
db.execSQL(QUERY_CREATE_DOCUMENTS);
db.execSQL(QUERY_CREATE_ROOT_EXTRA);
+ db.execSQL(QUERY_CREATE_LAST_BOOT_COUNT);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL("DROP TABLE " + TABLE_DOCUMENTS);
- db.execSQL("DROP TABLE " + TABLE_ROOT_EXTRA);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_DOCUMENTS);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_ROOT_EXTRA);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_LAST_BOOT_COUNT);
onCreate(db);
}
}
@@ -818,4 +881,16 @@
}
return results;
}
+
+ private static String getIdList(Set<String> ids) {
+ String result = "(";
+ for (final String id : ids) {
+ if (result.length() > 1) {
+ result += ",";
+ }
+ result += id;
+ }
+ result += ")";
+ return result;
+ }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
index ff4b89f..6d98e34 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
@@ -30,7 +30,7 @@
* Class containing MtpDatabase constants.
*/
class MtpDatabaseConstants {
- static final int DATABASE_VERSION = 4;
+ static final int DATABASE_VERSION = 5;
static final String DATABASE_NAME = "database";
static final int FLAG_DATABASE_IN_MEMORY = 1;
@@ -48,6 +48,11 @@
static final String TABLE_ROOT_EXTRA = "RootExtra";
/**
+ * Table containing last boot count.
+ */
+ static final String TABLE_LAST_BOOT_COUNT = "LastBootCount";
+
+ /**
* 'FROM' closure of joining TABLE_DOCUMENTS and TABLE_ROOT_EXTRA.
*/
static final String JOIN_ROOTS = createJoinFromClosure(
@@ -62,7 +67,13 @@
static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id";
static final String COLUMN_DOCUMENT_TYPE = "document_type";
static final String COLUMN_ROW_STATE = "row_state";
- static final String COLUMN_MAPPING_KEY = "column_mapping_key";
+ static final String COLUMN_MAPPING_KEY = "mapping_key";
+
+ /**
+ * Value for TABLE_LAST_BOOT_COUNT.
+ * Type: INTEGER
+ */
+ static final String COLUMN_VALUE = "value";
/**
* The state represents that the row has a valid object handle.
@@ -133,6 +144,9 @@
Root.COLUMN_CAPACITY_BYTES + " INTEGER," +
Root.COLUMN_MIME_TYPES + " TEXT NOT NULL);";
+ static final String QUERY_CREATE_LAST_BOOT_COUNT =
+ "CREATE TABLE " + TABLE_LAST_BOOT_COUNT + " (value INTEGER NOT NULL);";
+
/**
* Map for columns names to provide DocumentContract.Root compatible columns.
* @see SQLiteQueryBuilder#setProjectionMap(Map)
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 7211253..d4d4591 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -17,6 +17,7 @@
package com.android.mtp;
import android.content.ContentResolver;
+import android.content.UriPermission;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
@@ -25,6 +26,7 @@
import android.media.MediaFile;
import android.mtp.MtpConstants;
import android.mtp.MtpObjectInfo;
+import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
@@ -33,6 +35,8 @@
import android.provider.DocumentsContract.Root;
import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -42,6 +46,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -95,6 +100,21 @@
mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
mAppFuse = new AppFuse(TAG, new AppFuseCallback());
mIntentSender = new ServiceIntentSender(getContext());
+
+ // Check boot count and cleans database if it's first time to launch MtpDocumentsProvider
+ // after booting.
+ final int bootCount = Settings.Global.getInt(mResolver, Settings.Global.BOOT_COUNT, -1);
+ final int lastBootCount = mDatabase.getLastBootCount();
+ if (bootCount != -1 && bootCount != lastBootCount) {
+ mDatabase.setLastBootCount(bootCount);
+ final List<UriPermission> permissions = mResolver.getOutgoingPersistedUriPermissions();
+ final Uri[] uris = new Uri[permissions.size()];
+ for (int i = 0; i < permissions.size(); i++) {
+ uris[i] = permissions.get(i).getUri();
+ }
+ mDatabase.cleanDatabase(uris);
+ }
+
// TODO: Mount AppFuse on demands.
try {
mAppFuse.mount(getContext().getSystemService(StorageManager.class));
@@ -122,6 +142,7 @@
mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
mAppFuse = new AppFuse(TAG, new AppFuseCallback());
mIntentSender = intentSender;
+
// TODO: Mount AppFuse on demands.
try {
mAppFuse.mount(storageManager);
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index f9e8225..e49a935 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -19,6 +19,7 @@
import android.database.Cursor;
import android.mtp.MtpConstants;
import android.mtp.MtpObjectInfo;
+import android.net.Uri;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
@@ -26,6 +27,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import java.io.FileNotFoundException;
+import java.util.Arrays;
import static android.provider.DocumentsContract.Document.*;
import static com.android.mtp.MtpDatabase.strings;
@@ -1023,6 +1025,62 @@
assertFalse(mDatabase.getMapper().stopAddingDocuments(null));
}
+ public void testSetBootCount() {
+ assertEquals(0, mDatabase.getLastBootCount());
+ mDatabase.setLastBootCount(10);
+ assertEquals(10, mDatabase.getLastBootCount());
+ try {
+ mDatabase.setLastBootCount(-1);
+ fail();
+ } catch (IllegalArgumentException e) {}
+ }
+
+ public void testCleanDatabase() throws FileNotFoundException {
+ // Add tree.
+ addTestDevice();
+ addTestStorage("1");
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+ createDocument(100, "apple.txt", MtpConstants.FORMAT_TEXT, 1024),
+ createDocument(101, "orange.txt", MtpConstants.FORMAT_TEXT, 1024),
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ // Disconnect the device.
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ // Clean database.
+ mDatabase.cleanDatabase(new Uri[] {
+ DocumentsContract.buildDocumentUri(MtpDocumentsProvider.AUTHORITY, "3")
+ });
+
+ // Add tree again.
+ addTestDevice();
+ addTestStorage("1");
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] {
+ createDocument(100, "apple.txt", MtpConstants.FORMAT_TEXT, 1024),
+ createDocument(101, "orange.txt", MtpConstants.FORMAT_TEXT, 1024),
+ });
+ mDatabase.getMapper().stopAddingDocuments("2");
+
+ try (final Cursor cursor = mDatabase.queryChildDocuments(
+ strings(COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME), "2")) {
+ assertEquals(2, cursor.getCount());
+
+ // Persistent uri uses the same ID.
+ cursor.moveToNext();
+ assertEquals("3", cursor.getString(0));
+ assertEquals("apple.txt", cursor.getString(1));
+
+ // Others does not.
+ cursor.moveToNext();
+ assertEquals("5", cursor.getString(0));
+ assertEquals("orange.txt", cursor.getString(1));
+ }
+ }
+
private void addTestDevice() throws FileNotFoundException {
TestUtil.addTestDevice(mDatabase);
}
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index 57ba2b6..c8478f2 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Meer inligting oor hierdie drukker"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Sommige drukdienste is gedeaktiveer."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Kies drukdiens"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Sommige drukdienste is gedeaktiveer"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Soek tans vir drukkers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Geen drukdienste is geaktiveer nie"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Geen drukkers gekry nie"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Kan nie drukkers byvoeg nie"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Kies om drukker by te voeg"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Kies om te aktiveer"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Geaktiveerde dienste"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Aanbevole dienste"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Gedeaktiveerde dienste"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Alle dienste"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Druk tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kanselleer tans <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Drukkerfout by <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index a2182fb..d4426cc 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"ተጨማሪ የዚህ አታሚ መረጃ"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"አንዳንድ የህትመት አገልግሎቶች ተሰናክለዋል።"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"የህትመት አገልግሎት ይምረጡ"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"አንዳንድ የህትመት አገልግሎቶች ተሰናክለዋል"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"አታሚዎችን በመፈለግ ላይ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ምንም የህትመት አገልግሎቶች አልነቁም"</string>
<string name="print_no_printers" msgid="4869403323900054866">"ምንም አታሚዎች አልተገኙም"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"አታሚዎችን ማከል አልተቻለም"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"አታሚን ለማከል ይምረጡ"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"ለማንቃት ይምረጡ"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"የነቁ አገልግሎቶች"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"የሚመከሩ አገልግሎቶች"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"የተሰናከሉ አገልግሎቶች"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"ሁሉም አገልግሎቶች"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በማተም ላይ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ን በመተው ላይ"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"የአታሚ ስህተት <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index eab1339..2e1b6d0 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -65,11 +65,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"مزيد من المعلومات حول هذه الطابعة"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"بعض خدمات الطباعة معطَّلة."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"اختر خدمة طباعة"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"بعض خدمات الطباعة معطَّلة"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"البحث عن طابعات"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"لم يتم تمكين أي خدمات طباعة"</string>
<string name="print_no_printers" msgid="4869403323900054866">"لم يتم العثور على طابعات"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"تعذرت إضافة طابعات"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"اختر لإضافة طابعة"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"حدد للتمكين"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"الخدمات الممكنة"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"الخدمات الموصى بها"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"الخدمات المعطَّلة"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"جميع الخدمات"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"جارٍ طباعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"جارٍ إلغاء <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"خطا في الطابعة <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-az-rAZ/strings.xml b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
index bff477d..5490b84 100644
--- a/packages/PrintSpooler/res/values-az-rAZ/strings.xml
+++ b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Bu printer haqqında daha ətraflı məlumat"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Bəzi çap xidmətləri deaktiv edilib."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Çap xidmətini seçin"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Bəzi çap xidmətləri deaktiv edilib."</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printer axtarılır"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Heç bir çap xidməti aktiv edilməyib"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Heç bir printer tapılmadı"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Printerlər əlavə edilmədi"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Printer əlavə etmək üçün seçin"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Aktiv etmək üçün seçin"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Aktiv edilmiş xidmətlər"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Tövsiyə olunan xidmətlər"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Deaktiv edilmiş xidmətlər"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Bütün xidmətlər"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> çap edilir"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ləğv edilir"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer xətası <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index b28aa29..0574dae 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -62,11 +62,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Još informacija o ovom štampaču"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Neke usluge štampanja su onemogućene."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Izaberite uslugu štampanja"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Neke usluge štampanja su onemogućene"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Pretraga štampača"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nijedna usluga štampanja nije omogućena"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nije pronađen nijedan štampač"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Nije moguće dodati štampače"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Izaberite da biste dodali štampač"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Izaberite da biste omogućili"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Omogućene usluge"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Onemogućene usluge"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Štampa se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazuje se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Greška štampača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index e8de8ea..88af8e4 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Още информация за този принтер"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Някои услуги за отпечатване са деактивирани."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Избиране на услуга за отпечатване"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Някои услуги за отпечатване са деактивирани"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Търсене на принтери"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Няма активирани услуги за отпечатване"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Няма намерени принтери"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Не могат да се добавят принтери"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Изберете, за да добавите принтер"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Изберете, за да активирате"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Активирани услуги"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Препоръчителни услуги"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Деактивирани услуги"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Всички услуги"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се отпечатва"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"„<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“ се анулира"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка в принтера при „<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>“"</string>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index a1ca494..c61ef74 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4469836075319831821">"মুদ্রণ স্পোলার"</string>
+ <string name="app_label" msgid="4469836075319831821">"প্রিন্ট স্পোলার"</string>
<string name="more_options_button" msgid="2243228396432556771">"আরো বিকল্প"</string>
<string name="label_destination" msgid="9132510997381599275">"গন্তব্য"</string>
<string name="label_copies" msgid="3634531042822968308">"প্রতিলিপিগুলি"</string>
@@ -31,22 +31,22 @@
<string name="template_all_pages" msgid="3322235982020148762">"সমস্ত <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
<string name="template_page_range" msgid="428638530038286328">"<xliff:g id="PAGE_COUNT">%1$s</xliff:g> এর পরিসর"</string>
<string name="pages_range_example" msgid="8558694453556945172">"যেমন, ১—৫,৮,১১—১৩"</string>
- <string name="print_preview" msgid="8010217796057763343">"মুদ্রণ পূর্বরূপ"</string>
+ <string name="print_preview" msgid="8010217796057763343">"প্রিন্ট পূর্বরূপ"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"পূর্বরূপ দেখার জন্য PDF ভিউয়ার ইনস্টল করুন"</string>
- <string name="printing_app_crashed" msgid="854477616686566398">"মুদ্রণ অ্যাপ্লিকেশান ক্র্যাশ করছে"</string>
- <string name="generating_print_job" msgid="3119608742651698916">"মুদ্রণ কার্য তৈরি করা হচ্ছে"</string>
+ <string name="printing_app_crashed" msgid="854477616686566398">"প্রিন্ট অ্যাপ্লিকেশান ক্র্যাশ করছে"</string>
+ <string name="generating_print_job" msgid="3119608742651698916">"প্রিন্ট কার্য তৈরি করা হচ্ছে"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"PDF হিসাবে সংরক্ষণ করুন"</string>
<string name="all_printers" msgid="5018829726861876202">"সমস্ত মুদ্রক…"</string>
- <string name="print_dialog" msgid="32628687461331979">"মুদ্রণ ডায়লগ"</string>
+ <string name="print_dialog" msgid="32628687461331979">"প্রিন্ট ডায়লগ"</string>
<string name="current_page_template" msgid="1386638343571771292">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g> /<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
<string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="PAGE_COUNT">%2$d</xliff:g>টির মধ্যে <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> নম্বর পৃষ্ঠা"</string>
<string name="summary_template" msgid="8899734908625669193">"সারাংশ, <xliff:g id="COPIES">%1$s</xliff:g>টি অনুলিপি, কাগজের আকার <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
<string name="expand_handle" msgid="7282974448109280522">"প্রসারিত করার হ্যান্ডেল"</string>
<string name="collapse_handle" msgid="6886637989442507451">"সঙ্কুচিত করার হ্যান্ডেল"</string>
- <string name="print_button" msgid="645164566271246268">"মুদ্রণ করুন"</string>
+ <string name="print_button" msgid="645164566271246268">"প্রিন্ট করুন"</string>
<string name="savetopdf_button" msgid="2976186791686924743">"PDF হিসাবে সংরক্ষণ করুন"</string>
- <string name="print_options_expanded" msgid="6944679157471691859">"মুদ্রণ বিকল্প প্রসারিত হয়েছে"</string>
- <string name="print_options_collapsed" msgid="7455930445670414332">"মুদ্রণ বিকল্প সংকুচিত হয়েছে"</string>
+ <string name="print_options_expanded" msgid="6944679157471691859">"প্রিন্ট বিকল্প প্রসারিত হয়েছে"</string>
+ <string name="print_options_collapsed" msgid="7455930445670414332">"প্রিন্ট বিকল্প সংকুচিত হয়েছে"</string>
<string name="search" msgid="5421724265322228497">"অনুসন্ধান করুন"</string>
<string name="all_printers_label" msgid="3178848870161526399">"সমস্ত মুদ্রক"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"পরিষেবা যোগ করুন"</string>
@@ -61,12 +61,18 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"এই মুদ্রকটির বিষয়ে আরো তথ্য"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"কিছু মুদ্রণ পরিষেবা অক্ষম করা হয়েছে৷"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"মুদ্রণ পরিষেবা চয়ন করুন"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"কিছু মুদ্রণ পরিষেবা অক্ষম করা আছে"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"মুদ্রকগুলি অনুসন্ধান করা হচ্ছে"</string>
- <string name="print_no_print_services" msgid="8561247706423327966">"মুদ্রণ পরিষেবা সক্ষম নেই"</string>
+ <string name="print_no_print_services" msgid="8561247706423327966">"প্রিন্ট পরিষেবা সক্ষম নেই"</string>
<string name="print_no_printers" msgid="4869403323900054866">"কোনো মুদ্রক পাওয়া যায়নি"</string>
- <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রণ করা হচ্ছে"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"মুদ্রকগুলি যোগ করা যাবে না"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"মুদ্রক যোগ করতে নির্বাচন করুন"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"সক্ষম করতে নির্বাচন করুন"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"সক্ষম করা পরিষেবাগুলি"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"প্রস্তাবিত পরিষেবাগুলি"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"অক্ষম করা পরিষেবাগুলি"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"সমস্ত পরিষেবা"</string>
+ <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> প্রিন্ট করা হচ্ছে"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> বাতিল করা হচ্ছে"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> মুদ্রক ত্রুটি"</string>
<string name="blocked_notification_title_template" msgid="1175435827331588646">"মুদ্রক <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> অবরুদ্ধ করেছে"</string>
diff --git a/packages/PrintSpooler/res/values-bs-rBA/strings.xml b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
new file mode 100644
index 0000000..7465c3c
--- /dev/null
+++ b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2013 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"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="4469836075319831821">"Štampanje na čekanju"</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Više opcija"</string>
+ <string name="label_destination" msgid="9132510997381599275">"Odredište"</string>
+ <string name="label_copies" msgid="3634531042822968308">"Kopije"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Primjeraka:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Veličina papira"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Veličina papira:"</string>
+ <string name="label_color" msgid="1108690305218188969">"U boji"</string>
+ <string name="label_duplex" msgid="5370037254347072243">"Dvostrano"</string>
+ <string name="label_orientation" msgid="2853142581990496477">"Orijentacija"</string>
+ <string name="label_pages" msgid="7768589729282182230">"Stranicā"</string>
+ <string name="destination_default_text" msgid="5422708056807065710">"Odaberite štampač"</string>
+ <string name="template_all_pages" msgid="3322235982020148762">"Sve stranice (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
+ <string name="template_page_range" msgid="428638530038286328">"Opseg od <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
+ <string name="pages_range_example" msgid="8558694453556945172">"npr. 1—5,8,11—13"</string>
+ <string name="print_preview" msgid="8010217796057763343">"Pregled prije štampanja"</string>
+ <string name="install_for_print_preview" msgid="6366303997385509332">"Instaliraj PDF preglednik za prikaz"</string>
+ <string name="printing_app_crashed" msgid="854477616686566398">"Aplikacija za štampanje je prestala raditi"</string>
+ <string name="generating_print_job" msgid="3119608742651698916">"Kreiranje zadatka za štampu"</string>
+ <string name="save_as_pdf" msgid="5718454119847596853">"Sačuvaj kao PDF"</string>
+ <string name="all_printers" msgid="5018829726861876202">"Svi štampači…"</string>
+ <string name="print_dialog" msgid="32628687461331979">"Dijaloški okvir za štampanje"</string>
+ <string name="current_page_template" msgid="1386638343571771292">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g> /<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
+ <string name="page_description_template" msgid="6831239682256197161">"Strana <xliff:g id="CURRENT_PAGE">%1$d</xliff:g> od <xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
+ <string name="summary_template" msgid="8899734908625669193">"Rezime, primjeraka <xliff:g id="COPIES">%1$s</xliff:g>, veličina papira <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
+ <string name="expand_handle" msgid="7282974448109280522">"Regulator za proširivanje"</string>
+ <string name="collapse_handle" msgid="6886637989442507451">"Regulator za skupljanje"</string>
+ <string name="print_button" msgid="645164566271246268">"Štampaj"</string>
+ <string name="savetopdf_button" msgid="2976186791686924743">"Sačuvaj u PDF"</string>
+ <string name="print_options_expanded" msgid="6944679157471691859">"Opcije za štampanje su proširene"</string>
+ <string name="print_options_collapsed" msgid="7455930445670414332">"Opcije za štampanje su skupljene"</string>
+ <string name="search" msgid="5421724265322228497">"Traži"</string>
+ <string name="all_printers_label" msgid="3178848870161526399">"Svi štampači"</string>
+ <string name="add_print_service_label" msgid="5356702546188981940">"Dodaj uslugu"</string>
+ <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Okvir za pretraživanje je prikazan"</string>
+ <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Okvir za pretraživanje je skriven"</string>
+ <string name="print_add_printer" msgid="1088656468360653455">"Dodaj štampač"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Izaberite štampač"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Zaboravi ovaj štampač"</string>
+ <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+ <item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> štampač je pronađen</item>
+ <item quantity="few"><xliff:g id="COUNT_1">%1$s</xliff:g> štampača su pronađena</item>
+ <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> štampača je pronađeno</item>
+ </plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Više informacija o ovom štampaču"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Neke usluge za štampanje su isključene"</string>
+ <string name="print_searching_for_printers" msgid="6550424555079932867">"Traženje štampača"</string>
+ <string name="print_no_print_services" msgid="8561247706423327966">"Usluga za štampanje nije uključena"</string>
+ <string name="print_no_printers" msgid="4869403323900054866">"Nijedan štampač nije pronađen"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Ne mogu se dodati štampači"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Odaberite da biste dodali štampač"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Odaberite da biste uključili"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Uključene usluge"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Isključene usluge"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
+ <string name="printing_notification_title_template" msgid="295903957762447362">"Štampa se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+ <string name="failed_notification_title_template" msgid="2256217208186530973">"Greška pri štampanju <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+ <string name="blocked_notification_title_template" msgid="1175435827331588646">"Štampač je blokirao <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+ <string name="cancel" msgid="4373674107267141885">"Otkaži"</string>
+ <string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
+ <string name="no_connection_to_printer" msgid="2159246915977282728">"Nema konekcije sa štampačem"</string>
+ <string name="reason_unknown" msgid="5507940196503246139">"nepoznat"</string>
+ <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nedostupan"</string>
+ <string name="print_service_security_warning_title" msgid="2160752291246775320">"Zaista želite koristiti uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
+ <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Moguće je da dokument prije štampanja prođe kroz jedan ili više servera."</string>
+ <string-array name="color_mode_labels">
+ <item msgid="7602948745415174937">"Crno-bijela"</item>
+ <item msgid="2762241247228983754">"U boji"</item>
+ </string-array>
+ <string-array name="duplex_mode_labels">
+ <item msgid="3882302912790928315">"Nije podržano"</item>
+ <item msgid="7296563835355641719">"Po dužoj strani"</item>
+ <item msgid="79513688117503758">"Po kraćoj strani"</item>
+ </string-array>
+ <string-array name="orientation_labels">
+ <item msgid="4061931020926489228">"Uspravno"</item>
+ <item msgid="3199660090246166812">"Vodoravno"</item>
+ </string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Nije moguće pisati u fajl"</string>
+ <string name="print_error_default_message" msgid="8602678405502922346">"Nažalost, nije uspjelo. Pokušajte ponovo."</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Ponovi"</string>
+ <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Štampač trenutno nije dostupan."</string>
+ <string name="print_preparing_preview" msgid="3939930735671364712">"Priprema pregleda..."</string>
+</resources>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index aa6f992..482100a 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Més informació sobre aquesta impressora"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Hi ha serveis d\'impressió que estan desactivats."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Selecció del servei d\'impressió"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alguns serveis d\'impressió estan desactivats"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Cerca d\'impressores"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No hi ha cap servei d\'impressió activat"</string>
<string name="print_no_printers" msgid="4869403323900054866">"No s\'ha trobat cap impressora"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"No poden afegir impressores"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Selecciona per afegir una impressora"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Selecciona\'ls per activar-los"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Serveis activats"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Serveis recomanats"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Serveis desactivats"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Tots els serveis"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"S\'està imprimint <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"S\'està cancel·lant <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error d\'impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 4bc22d4..a4c412c 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -63,11 +63,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Další informace o této tiskárně"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Některé tiskové služby nejsou aktivovány."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Zvolte službu tisku"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Některé tiskové služby nejsou aktivovány"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhledávání tiskáren"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nejsou aktivovány žádné tiskové služby"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nebyly nalezeny žádné tiskárny"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Tiskárny nelze přidat"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Výběrem přidáte tiskárnu"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Výběrem službu aktivujete"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Aktivované služby"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Doporučené služby"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Deaktivované služby"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Všechny služby"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Tisk úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Rušení úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tiskárny u úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index b8be624..9ee252167 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Flere oplysninger om denne printer"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Nogle udskrivningstjenester er deaktiveret."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Vælg udskriftstjeneste"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Nogle udskrivningstjenester er deaktiveret"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Søger efter printere"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ingen udskrivningstjenester er aktiveret"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Der blev ikke fundet nogen printere"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Der kan ikke tilføjes printere"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Vælg for at tilføje en printer"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Vælg for at aktivere"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Aktiverede tjenester"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Anbefalede tjenester"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Deaktiverede tjenester"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Alle tjenester"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> udskrives"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annulleres"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Udskriften <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> mislykkedes"</string>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index bcb7e73..ef451b7 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Weitere Informationen über diesen Drucker"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Einige Druckdienste sind deaktiviert."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Druckdienst auswählen"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Einige Druckdienste sind deaktiviert"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Suche nach Druckern"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Keine Druckdienste aktiviert"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Keine Drucker gefunden"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Hinzufügen von Druckern nicht möglich"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Auswählen, um Drucker hinzuzufügen"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Zum Aktivieren auswählen"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Aktivierte Dienste"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Empfohlene Dienste"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Deaktivierte Dienste"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Alle Dienste"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird gedruckt..."</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> wird abgebrochen..."</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Druckerfehler <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index d9a4aeb..9be81c1 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Περισσότερες πληροφορίες σχετικά με αυτόν τον εκτυπωτή"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Κάποιες υπηρ. εκτύπωσης είναι απενεργοποιημένες."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Επιλέξτε υπηρεσία εκτύπωσης"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Ορισμένες υπηρ. εκτύπωσης είναι απενεργοποιημένες"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Αναζήτηση για εκτυπωτές"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Δεν έχουν ενεργοποιηθεί υπηρεσίες εκτύπωσης"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Δεν βρέθηκαν εκτυπωτές"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Δεν είναι δυνατή η προσθήκη εκτυπωτών"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Επιλέξτε για την προσθήκη εκτυπωτή"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Επιλέξτε για ενεργοποίηση"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Ενεργοποιημένες υπηρεσίες"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Προτεινόμενες υπηρεσίες"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Υπηρεσίες για άτομα με αναπηρία"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Όλες οι υπηρεσίες"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Εκτύπωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ακύρωση <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Σφάλμα εκτυπωτή <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-en-rAU/strings.xml b/packages/PrintSpooler/res/values-en-rAU/strings.xml
index d8a9437..8b58011 100644
--- a/packages/PrintSpooler/res/values-en-rAU/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rAU/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Some print services are disabled."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Some print services are disabled"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
<string name="print_no_printers" msgid="4869403323900054866">"No printers found"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Cannot add printers"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Select to add printer"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Select to enable"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Enabled services"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"All services"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index d8a9437..8b58011 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Some print services are disabled."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Some print services are disabled"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
<string name="print_no_printers" msgid="4869403323900054866">"No printers found"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Cannot add printers"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Select to add printer"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Select to enable"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Enabled services"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"All services"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index d8a9437..8b58011 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Some print services are disabled."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Some print services are disabled"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
<string name="print_no_printers" msgid="4869403323900054866">"No printers found"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Cannot add printers"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Select to add printer"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Select to enable"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Enabled services"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Recommended services"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Disabled services"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"All services"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Printing <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelling <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printer error <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 19cbee7..8fa6094 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Más información sobre esta impresora"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Hay servicios de impresión inhabilitados."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Elegir servicio de impresión"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Hay servicios de impresión inhabilitados"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
<string name="print_no_printers" msgid="4869403323900054866">"No se encontraron impresoras"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"No es posible agregar impresoras"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Seleccionar para agregar impresoras"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Seleccionar para habilitar"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Servicios habilitados"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Servicios recomendados"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimiendo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index d13ccda..a0ce57a 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Más información sobre esta impresora"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Algunos servicios de impresión están inhabilitados."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Seleccionar servicio de impresión"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Algunos servicios de impresión están inhabilitados"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
<string name="print_no_printers" msgid="4869403323900054866">"No se encontraron impresoras"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"No se pueden añadir impresoras"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Seleccionar para añadir una impresora"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Seleccionar para habilitar"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Servicios habilitados"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Servicios recomendados"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Servicios inhabilitados"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Todos los servicios"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimiendo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error de impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
@@ -91,7 +97,7 @@
<item msgid="3199660090246166812">"Horizontal"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Error al escribir en el archivo"</string>
- <string name="print_error_default_message" msgid="8602678405502922346">"No ha funcionado. Repítelo."</string>
+ <string name="print_error_default_message" msgid="8602678405502922346">"No ha funcionado. Prueba de nuevo."</string>
<string name="print_error_retry" msgid="1426421728784259538">"Reintentar"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Esta impresora no está disponible en este momento."</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Preparando vista previa…"</string>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index f03eb37..6dde083 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Lisateave selle printeri kohta"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Mõned printimisteenused on keelatud."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Prinditeenuse valimine"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Mõned printimisteenused on keelatud"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printerite otsimine"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ühtegi printimisteenust pole lubatud"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Printereid ei leitud"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Printereid ei saa lisada"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Valige printeri lisamiseks"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Valige lubamiseks"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Lubatud teenused"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Soovitatud teenused"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Keelatud teenused"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Kõik teenused"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> printimine"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prinditöö <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> tühistamine"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri viga: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index d4255e2..858444b 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Informazio gehiago inprimagailuari buruz"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Desgaituta daude inprimatzeko zerbitzu batzuk."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Aukeratu inprimatze-zerbitzua"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Desgaituta daude inprimatzeko zerbitzu batzuk"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Inprimagailuak bilatzen"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ez dago gaituta inprimatzeko zerbitzurik"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Ez da inprimagailurik aurkitu"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Ezin da gehitu inprimagailurik"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Hautatu inprimagailua gehitzeko"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Hautatu gehitzeko"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Gaitutako zerbitzuak"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Gomendatutako zerbitzuak"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Desgaitutako zerbitzuak"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Zerbitzu guztiak"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzen"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bertan behera uzten"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Errorea <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> inprimatzean"</string>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 907123c..7c69c27 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"اطلاعات بیشتر درباره چاپگر"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"بعضی از خدمات چاپ غیرفعال هستند."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"انتخاب سرویس چاپ"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"بعضی از خدمات چاپ غیرفعال هستند"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"درحال جستجوی چاپگرها"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"هیچ خدمات چاپی فعال نیست"</string>
<string name="print_no_printers" msgid="4869403323900054866">"هیچ چاپگری یافت نشد"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"نمیتوان چاپگر اضافه کرد"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"برای افزودن چاپگر، انتخاب کنید"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"برای فعال کردن، انتخاب کنید"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"خدمات فعال"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"خدمات توصیهشده"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"خدمات غیرفعال"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"همه خدمات"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"در حال چاپ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"در حال لغو <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"خطای چاپگر <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index f57b884..dfd98f8 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Lisätietoja tästä tulostimesta"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Osa tulostuspalveluista on poistettu käytöstä."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Valitse tulostuspalvelu"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Osa tulostuspalveluista on poistettu käytöstä."</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Etsitään tulostimia"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ei käytössä olevia tulostuspalveluita"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Tulostimia ei löydy"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Tulostimien lisääminen ei onnistu."</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Valitse palvelu tulostimen lisäämistä varten."</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Valitse käyttöön otettavat palvelut."</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Käytössä olevat palvelut"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Suositellut palvelut"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Käytöstä poistetut palvelut"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Kaikki palvelut"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Tulostetaan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Peruutetaan työ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Tulostinvirhe työlle <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 949ba55..a95d565 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Plus d\'information sur cette imprimante"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Certains services d\'impression sont désactivés."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Certains services d\'impression sont désactivés"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours..."</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Aucun service d\'impression activé"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Aucune imprimante trouvée"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Impossible d’ajouter des imprimantes"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Sélectionnez pour ajouter une imprimante"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Sélectionner pour activer"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Services activés"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Services recommandés"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Services désactivés"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Impression de <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> en cours…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression : « <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> »"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 1fcc040..dd1f490 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Plus d\'informations sur cette imprimante"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Certains services d\'impression sont désactivés."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Certains services d\'impression sont désactivés."</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Aucun service d\'impression activé"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Aucune imprimante trouvée"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Impossible d\'ajouter des imprimantes"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Sélectionnez pour ajouter une imprimante."</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Sélectionnez pour activer."</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Services activés"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Services recommandés"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Services désactivés"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Tous les services"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Impression de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annulation de \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" en cours…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erreur impression pour \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index 2e60960..81e080e 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Máis información sobre esta impresora"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Algúns servizos de impresión están desactivados."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Escoller servizo de impresión"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Algúns servizos de impresión están desactivados"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Busca de impresoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Non hai servizos de impresión activados"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Non se atopou ningunha impresora"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Non se poden engadir impresoras"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Selecciona un servizo para engadirlle impresora"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Selecciona un servizo para activalo"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Servizos activados"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Servizos recomendados"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Servizos desactivados"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Todos os servizos"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impresora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-gu-rIN/strings.xml b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
index 4ba969c..44ede86 100644
--- a/packages/PrintSpooler/res/values-gu-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"આ પ્રિન્ટર વિશે વધુ માહિતી"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"કેટલીક છાપ સેવાઓ અક્ષમ કરેલ છે."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"પ્રિન્ટ સેવા પસંદ કરો"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"કેટલીક છાપવાની સેવાઓ અક્ષમ કરેલ છે"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"પ્રિન્ટર્સ માટે શોધી રહ્યું છે"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"કોઈ છાપ સેવાઓ સક્ષમ કરેલ નથી"</string>
<string name="print_no_printers" msgid="4869403323900054866">"કોઈ પ્રિન્ટર મળ્યા નથી"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"પ્રિન્ટર્સ ઉમેરી શકતાં નથી"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"પ્રિન્ટર ઉમેરવા માટે પસંદ કરો"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"સક્ષમ કરવા માટે પસંદ કરો"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"સક્ષમ કરેલી સેવાઓ"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"ભલામણ કરેલી સેવાઓ"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"અક્ષમ કરેલી સેવાઓ"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"બધી સેવાઓ"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> છાપી રહ્યાં છે"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ને રદ કરી રહ્યું છે"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"પ્રિન્ટર ભૂલ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 1061346..f75630e 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"इस प्रिंटर के बारे में अधिक जानकारी"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"कुछ प्रिंट सेवाएं अक्षम हैं."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"प्रिंट सेवा चुनें"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"कुछ प्रिंट सेवाएं अक्षम हैं"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर खोज रहा है"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"कोई भी प्रिंट सेवा सक्षम नहीं है"</string>
<string name="print_no_printers" msgid="4869403323900054866">"कोई प्रिंटर नहीं मिले"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"प्रिंटर जोड़े नहीं जा सकते"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"प्रिंटर जोड़ने के लिए चुनें"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"सक्षम करने के लिए चुनें"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"सक्षम सेवाएं"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"सुझाई गई सेवाएं"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"अक्षम सेवाएं"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"सभी सेवाएं"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> प्रिंट हो रहा है"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द हो रहा है"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 4a7d29f..bd29d02 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -62,11 +62,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Više informacija o ovom pisaču"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Neke su usluge ispisa onemogućene."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Odaberite uslugu ispisa"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Neke su usluge ispisa onemogućene"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Traženje pisača"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nije omogućena nijedna usluga ispisa"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nije pronađen nijedan pisač"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Ne možete dodati pisače"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Odaberite da biste dodali pisač"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Odaberite za omogućavanje"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Omogućene usluge"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Preporučene usluge"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Onemogućene usluge"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Sve usluge"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Ispisivanje <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazivanje zadatka <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Pogreška pisača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 5aae2e4..356cb76 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"További információ erről a nyomtatóról"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Egyes nyomtatási szolgáltatások le vannak tiltva."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Nyomtatási szolgáltatás kiválasztása"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Egyes nyomtatási szolgáltatások le vannak tiltva"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Nyomtatók keresése"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nincs engedélyezett nyomtatási szolgáltatás"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nem található nyomtató"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Nem lehet nyomtatókat hozzáadni"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Nyomtató hozzáadásához válassza ki"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Az engedélyezéshez válassza ki"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Engedélyezett szolgáltatások"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Javasolt szolgáltatások"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Letiltott szolgáltatások"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Minden szolgáltatás"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> nyomtatása"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"A(z) <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> törlése"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Nyomtatási hiba: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 179c384..2d10166 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Հավելյալ տեղեկություններ այս տպիչի մասին"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Տպելու որոշ ծառայությունները կասեցված են:"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Ընտրեք տպելու ծառայությունը"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Տպելու որոշ ծառայությունները կասեցված են"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Տպիչների որոնում"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ակտիվացված տպման ծառայություններ չկան"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Տպիչներ չեն գտնվել"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Չեն կարող ավելացնել տպիչներ"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Ընտրեք՝ տպիչ ավելացնելու համար"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Ընտրեք՝ միացնելու համար"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Միացված ծառայությունները"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Խորհուրդ տրվող ծառայությունները"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Կասեցված ծառայությունները"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Բոլոր ծառայությունները"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Տպվում է՝ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ը չեղարկվում է"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Տպիչի սխալ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 7286f7a..8e20d27 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Informasi selengkapnya tentang printer ini"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Beberapa layanan cetak dinonaktifkan."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Pilih layanan cetak"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Beberapa layanan cetak dinonaktifkan"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari printer"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Tidak ada layanan cetak yang aktif"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Tidak ditemukan printer"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Tidak dapat menambahkan printer"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Pilih untuk menambahkan printer"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Pilih untuk mengaktifkan"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Layanan diaktifkan"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Layanan yang disarankan"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Layanan dinonaktifkan"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Semua layanan"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Mencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Ada kesalahan printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 9ea49a9..73660fb 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Frekari upplýsingar um þennan prentara"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Hluti prentþjónustunnar er óvirkur."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Veldu prentþjónustu"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Hluti prentþjónustunnar er óvirkur"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Leitar að prentara"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Engin prentþjónusta er virk"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Engir prentarar fundust"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Ekki er hægt að bæta við prenturum"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Veldu til að bæta prentara við"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Veldu til að virkja"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Virkjaðar þjónustur"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Þjónusta sem mælt er með"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Þjónusta við fatlaða"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Öll þjónusta"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Prentar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hættir við <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Prentaravilla <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index c19d012..46a570d 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Ulteriori informazioni su questa stampante"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Alcuni servizi di stampa sono disattivati."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Scegli servizio di stampa"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alcuni servizi di stampa sono disattivati"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Ricerca di stampanti"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Non è stato attivato alcun servizio di stampa"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nessuna stampante trovata"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Impossibile aggiungere stampanti"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Seleziona per aggiungere stampanti"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Seleziona per attivare"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Servizi abilitati"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Servizi consigliati"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Servizi disattivati"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Tutti i servizi"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Stampa di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Annullamento di <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Errore della stampante: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index 00bf27c..c26c3d1 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -63,11 +63,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"מידע נוסף על מדפסת זו"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"שירותי הדפסה מסוימים מושבתים."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"בחר שירות הדפסה"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"שירותי הדפסה מסוימים מושבתים"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"מחפש מדפסות"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"לא הופעלו שירותי הדפסה"</string>
<string name="print_no_printers" msgid="4869403323900054866">"לא נמצאו מדפסות"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"לא ניתן להוסיף מדפסות"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"בחר כדי להוסיף מדפסת"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"בחר כדי להפעיל"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"שירותים מופעלים"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"שירותים מומלצים"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"שירותים מושבתים"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"כל השירותים"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"מדפיס את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"מבטל את <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"שגיאת מדפסת ב-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index e0fc79a..a6e243f 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"このプリンタの詳細"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"一部の印刷サービスは無効になっています。"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"印刷サービスの選択"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"一部の印刷サービスは無効になっています"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"プリンタの検索中"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"使用できる印刷サービスがありません"</string>
<string name="print_no_printers" msgid="4869403323900054866">"プリンタが見つかりません"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"プリンタは追加できません"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"選択してプリンタを追加"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"選択して有効にする"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"有効になっているサービス"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"推奨されているサービス"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"無効になっているサービス"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"すべてのサービス"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>を印刷しています"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>をキャンセルしています"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"プリンタエラー: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index ad1468a..2608ed4 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> — <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"დამატებითი ინფორმაცია ამ პრინტერის შესახებ"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"ბეჭდვის ზოგიერთი სერვისი გათიშულია."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"აირჩიეთ ბეჭდვის სერვისი"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"ბეჭდვის ზოგიერთი სერვისი გათიშულია"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"მიმდინარეობს პრინტერების ძიება"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ბეჭდვის სერვისები გააქტიურებული არ არის"</string>
<string name="print_no_printers" msgid="4869403323900054866">"პრინტერები ვერ მოიძებნა"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"პრინტერების დამატება ვერ მოხერხდება"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"აირჩიეთ პრინტერის დასამატებლად"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"აირჩიეთ ჩასართავად"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"ჩართული სერვისები"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"რეკომენდებული სერვისები"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"გათიშული სერვისები"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"ყველა სერვისი"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"იბეჭდება <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"მიმდინარეობს <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>-ის გაუქმება"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ბეჭდვის შეცდომა <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index d0337a6..def0c3c 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Осы принтер туралы қосымша ақпарат"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Кейбір басып шығару қызметтері өшірілген."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Принтер қызметін таңдау"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Кейбір басып шығару қызметтері өшірілген."</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлерді іздеу"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Басып шығару қызметтері қосылмаған"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Ешқандай принтер табылмады"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Принтерлерді қосу мүмкін емес"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Принтерді қосу үшін таңдаңыз"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Қосу үшін таңдаңыз"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Қосылған қызметтер"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Ұсынылған қызметтер"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Өшірілген қызметтер"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Барлық қызметтер"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> басып шығарылуда"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> жұмысын тоқтатуда"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> принтер қателігі"</string>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index c9431e9..24048cf 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"ព័ត៌មានបន្ថែមអំពីម៉ាស៊ីបោះពុម្ពនេះ"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"សេវាកម្មបោះពុម្ពមួយចំនួនត្រូវបានបិទដំណើរការ"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"ជ្រើសសេវាបោះពុម្ព"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"សេវាកម្មបោះពុម្ពមួយចំនួនត្រូវបានបិទដំណើរការ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ស្វែងរកម៉ាស៊ីនបោះពុម្ព"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"គ្មានការបើកដំណើរការសេវាបោះពុម្ពទេ"</string>
<string name="print_no_printers" msgid="4869403323900054866">"រកមិនឃើញម៉ាស៊ីនបោះពុម្ព"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"មិនអាចបន្ថែមម៉ាស៊ីនបោះពុម្ពបានទេ"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"ជ្រើសដើម្បីបន្ថែមម៉ាស៊ីនបោះពុម្ព"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"ជ្រើសដើម្បីបើកដំណើរការ"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"សេវាកម្មដែលបើកដំណើរការ"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"សេវាកម្មដែលបានណែនាំ"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"សេវាកម្មដែលបិទដំណើរការ"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"សេវាកម្មទាំងអស់"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"កំពុងបោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"ការបោះបង់ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"កំហុសម៉ាស៊ីនបោះពុម្ព <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index fc5149a..af20965 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"ಈ ಪ್ರಿಂಟರ್ ಬಗ್ಗೆ ಇನ್ನಷ್ಟು ಮಾಹಿತಿ"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"ಕೆಲವು ಮುದ್ರಣ ಸೇವೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"ಮುದ್ರಣ ಸೇವೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"ಕೆಲವು ಮುದ್ರಣ ಸೇವೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ಪ್ರಿಂಟರ್ಗಳಿಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ಯಾವುದೇ ಮುದ್ರಣ ಸೇವೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿಲ್ಲ"</string>
<string name="print_no_printers" msgid="4869403323900054866">"ಯಾವುದೇ ಮುದ್ರಕಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"ಪ್ರಿಂಟರ್ಗಳನ್ನು ಸೇರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"ಪ್ರಿಂಟರ್ ಸೇರಿಸಲು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"ಸಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"ಸಕ್ರಿಯಗೊಳಿಸಲಾದ ಸೇವೆಗಳು"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"ಶಿಫಾರಸು ಮಾಡಲಾದ ಸೇವೆಗಳು"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾದ ಸೇವೆಗಳು"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"ಎಲ್ಲ ಸೇವೆಗಳು"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ಮುದ್ರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ರದ್ದು ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ಮುದ್ರಕ ದೋಷ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 2faff1f..0b297a2 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"이 프린터에 대한 정보 더보기"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"프린트 서비스 일부가 사용 중지되었습니다."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"인쇄 서비스 선택"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"프린트 서비스 일부가 사용 중지되었습니다."</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"프린터 검색 중"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"사용 가능한 프린트 서비스 없음"</string>
<string name="print_no_printers" msgid="4869403323900054866">"프린터 없음"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"프린터를 추가할 수 없음"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"프린터를 추가하려면 선택하세요."</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"사용 설정하려면 선택하세요."</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"사용 설정된 서비스"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"권장 서비스"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"사용 중지된 서비스"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"모든 서비스"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 인쇄 중"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> 취소 중"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"프린터 오류: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index a01e4a8..85b2526 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Бул принтер жөнүндө көбүрөөк маалымат"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Басып чыгаруу кызматтарынын айрымы өчүрүлгөн."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Принтер кызматын тандоо"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Басып чыгаруу кызматтарынын айрымы өчүрүлгөн"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлер изделүүдө"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Принтер-кызматтары иштетилген эмес"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Принтерлер табылган жок"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Принтерлер кошулбай жатат"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Принтер кошуу үчүн тандаңыз"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Иштетүү үчүн тандаңыз"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Иштетилген кызматтар"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Сунушталган кызматтар"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Өчүрүлгөн кызматтар"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Бардык кызматтар"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> басылууда"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> токтотулууда"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерде ката кетти: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index b5d13b5..81ace83 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"ຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບເຄື່ອງພິມນີ້"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"ບາງການບໍລິການພິມຖືກປິດນຳໃຊ້."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"ເລືອກບໍລິການການພິມ"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"ບາງການບໍລິການພິມຖືກປິດການນຳໃຊ້"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ກຳລັງຊອກຫາເຄື່ອງພິມ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ບໍ່ມີການບໍລິການພິມເປີດໃຊ້ງານໄວ້"</string>
<string name="print_no_printers" msgid="4869403323900054866">"ບໍ່ພົບເຄື່ອງພິມ"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"ບໍ່ສາມາດເພີ່ມເຄື່ອງພິມໄດ້"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"ເລືອກເພື່ອເພີ່ມເຄື່ອງພິມ"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"ເລືອກເພື່ອເປີດໃຊ້"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"ບໍລິການທີ່ເປີດໃຊ້"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"ບໍລິການທີ່ແນະນຳ"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"ບໍລິການທີ່ຖືກປິດການນຳໃຊ້"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"ບໍລິການທັງໝົດ"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"ກຳລັງພິມ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"ກຳລັງຍົກເລີກ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ເຄື່ອງພິມເກີດຂໍ້ຜິດພາດ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 3b8f143..40bc7f1 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -63,11 +63,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"„<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g>“ – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Daugiau informacijos apie šį spausdintuvą"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Kai kurios spausdinimo paslaugos išjungtos."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Pasirinkite spausdinimo paslaugą"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Kai kurios spausdinimo paslaugos išjungtos"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Ieškoma spausdintuvų"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Neįgalinta jokių spausdinimo paslaugų"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nerasta spausdintuvų"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Nepavyko pridėti spausdintuvų"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Pasirinkite, kad pridėtumėte spausdintuvą"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Pasirinkite, kad įgalintumėte"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Įgalintos paslaugos"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Rekomenduojamos paslaugos"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Išjungtos paslaugos"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Visos paslaugos"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Spausdinama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Atšaukiama: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Spausdintuvo klaida: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 762d0bd..11e689b 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -62,11 +62,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> — <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Plašāka informācija par šo printeri"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Daži drukas pakalpojumi ir atspējoti."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Izvēlieties drukāšanas pakalpojumu"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Daži drukas pakalpojumi ir atspējoti."</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printeru meklēšana"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nav iespējots neviens drukas pakalpojums"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Netika atrasts neviens printeris."</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Nevar pievienot printerus"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Atlasiet, lai pievienotu printeri"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Izvēlieties, lai iespējotu"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Iespējotie pakalpojumi"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Ieteiktie pakalpojumi"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Atspējotie pakalpojumi"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Visi pakalpojumi"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Notiek darba <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> drukāšana…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Pārtrauc drukas darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printera kļūda ar darbu <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index de6d3e9..bc2b498 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Повеќе информации за овој печатач"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Некои услуги за печатење се оневозможени."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Избери услуга печатење"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Некои услуги за печатење се оневозможени"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Пребарување печатачи"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Нема овозможени услуги за печатење"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Не се пронајдени печатачи"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Не може да се додадат печатачи"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Изберете додавање печатач"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Изберете да се овозможи"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Овозможени услуги"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Препорачани услуги"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Оневозможени услуги"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Сите услуги"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се печати"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> се откажува"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка при печатење <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index 7a33e14..ade7fb39 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"ഈ പ്രിന്ററിനെ കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾ"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"ചില പ്രിന്റ് സേവനങ്ങൾ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"പ്രിന്റ് സേവനം തിരഞ്ഞെടുക്കുക"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"ചില പ്രിന്റ് സേവനങ്ങൾ പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"പ്രിന്ററുകൾക്കായി തിരയുന്നു"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"പ്രിന്റ് സേവനങ്ങളൊന്നും പ്രവർത്തനക്ഷമാക്കിയിട്ടില്ല"</string>
<string name="print_no_printers" msgid="4869403323900054866">"പ്രിന്ററുകളൊന്നും കണ്ടെത്തിയില്ല"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"പ്രിന്ററുകൾ ചേർക്കാൻ കഴിയില്ല"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"പ്രിന്റർ ചേർക്കാൻ തിരഞ്ഞെടുക്കുക"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"പ്രവർത്തനക്ഷമമാക്കാൻ തിരഞ്ഞെടുക്കുക"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"പ്രവർത്തനക്ഷമമാക്കിയ സേവനങ്ങൾ"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"ശുപാർശ ചെയ്യപ്പെടുന്ന സേവനങ്ങൾ"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"പ്രവർത്തനരഹിതമാക്കിയ സേവനങ്ങൾ"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"എല്ലാ സേവനങ്ങളും"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> പ്രിന്റുചെയ്യുന്നു"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> റദ്ദാക്കുന്നു"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"പ്രിന്റർ പിശക് <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index c94e56d..133d88c 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Энэ хэвлэгчийн талаарх дэлгэрэнгүй мэдээлэл"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Зарим хэвлэх үйлчилгээг идэвхгүй болгосон байна."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Хэвлэх үйлчилгээг сонгох"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Зарим хэвлэх үйлчилгээг идэвхгүй болгосон байна"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Принтер хайж байна"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Хэвлэх үйлчилгээг идэвхжүүлээгүй"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Принтер олдсонгүй"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Хэвлэгч нэмэх боломжгүй байна"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Хэвлэгч нэмэхийн тулд сонгох"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Идэвхжүүлэхийн тулд сонгох"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Идэвхжүүлсэн үйлчилгээ"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Санал болгосон үйлчилгээ"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Идэвхгүй болгосон үйлчилгээ"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Бүх үйлчилгээ"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Хэвлэж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Цуцлаж байна <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Принтерийн алдаа <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index ab25010..2b3b29f 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"या प्रिंटर विषयी अधिक माहिती"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"काही मुद्रण सेवा अक्षम केल्या आहेत."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"मुद्रण सेवा निवडा"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"काही मुद्रण सेवा अक्षम केल्या आहेत"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर शोधत आहे"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"कोणत्याही मुद्रण सेवा सक्षम केलेल्या नाहीत"</string>
<string name="print_no_printers" msgid="4869403323900054866">"कोणतेही प्रिंटर आढळले नाही"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"प्रिंटर जोडू शकत नाही"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"प्रिंटर जोडण्यासाठी निवडा"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"सक्षम करण्यासाठी निवडा"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"सक्षम केलेल्या सेवा"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"शिफारस केलेल्या सेवा"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"अक्षम केलल्या सेवा"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"सर्व सेवा"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करीत आहे"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करीत आहे"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर त्रुटी <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index 917ae8a..73104e1 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Maklumat lanjut tentang pencetak ini"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Sesetengah perkhidmatan cetak dilumpuhkan."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Pilih perkhidmatan cetak"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Sesetengah perkhidmatan cetak dilumpuhkan"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari pencetak"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Perkhidmatan cetak tidak didayakan"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Tiada pencetak ditemui"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Tidak dapat menambahkan pencetak"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Pilih untuk menambahkan pencetak"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Pilih untuk mendayakan"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Perkhidmatan yang didayakan"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Perkhidmatan yang disyorkan"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Perkhidmatan yang dilumpuhkan"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Semua perkhidmatan"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Mencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Membatalkan <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Ralat pencetak <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index 4d4c95b..8cec068 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"ဤပရင်တာ အကြောင်း ပိုမိုလေ့လာပါ"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"ပရင့်ထုတ်ရေး အချို့ဝန်ဆောင်မှုများကို ပိတ်ထားပါသည်။"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"စာထုတ်ရန် ဝန်ဆောင်မှုကို ရွေးချယ်ပါ"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"အချို့ပုံနှိပ်ဝန်ဆောင်မှုများကို ပိတ်ထားပါသည်"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"စာထုတ်စက်များကို ရှာနေပါသည်"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ပုံနှိပ်ထုတ်ယူရေး ဝန်ဆောင်မှုများ ဖွင့်မထားပါ"</string>
<string name="print_no_printers" msgid="4869403323900054866">"စာထုတ်စက် တစ်ခုမှ မတွေ့ရှိပါ"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"ပုံနှိပ်စက်များကို ထည့်၍မရပါ"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"ပုံနှိပ်စက်ထည့်ရန် ရွေးပါ"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"ဖွင့်ရန် ရွေးပါ"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"ဖွင့်ထားသည့် ဝန်ဆောင်မှုများ"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"အကြံပြုထားသည့် ဝန်ဆောင်မှုများ"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"ပိတ်ထားသည့် ဝန်ဆောင်မှုများ"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"ဝန်ဆောင်မှုများ အားလုံး"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို စာထုတ်နေပါသည်"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ကို ပယ်ဖျက်နေပါသည်"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"စာထုတ်စက်မှ အမှား <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index 9efa5d1..0a6f6c3 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Mer informasjon om denne printeren"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Noen utskriftstjenester er slått av."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Velg utskriftstjeneste"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Noen utskriftstjenester er slått av"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Søker etter skrivere"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ingen utskriftstjenester er slått på"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Fant ingen skrivere"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Kan ikke legge til skrivere"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Velg for å legge til skrivere"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Velg for å slå på"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Tjenester som er slått på"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Anbefalte tjenester"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Tjenester som er slått av"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Alle tjenester"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Skriver ut <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Skriverfeil <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index 281a65d..e12c8df 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"यस प्रिन्टरको बारेमा थप जानकारी"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"केही मुद्रण सेवाहरू असक्षम छन्।"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"प्रिन्ट सेवा छनौट गर्नुहोस्"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"केही मुद्रण सम्बन्धी सेवाहरूलाई असक्षम गरिएको छ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिन्टरहरू खोज्दै"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"कुनै पनि मुद्रण सेवाहरू सक्रिय छैनन्"</string>
<string name="print_no_printers" msgid="4869403323900054866">"कुनै प्रिन्टरहरू भेटाइएन"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"प्रिन्टरहरू थप्न सक्दैन"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"प्रिन्टर थप्नका लागि चयन गर्नुहोस्"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"सक्षम गर्नका लागि चयन गर्नुहोस्"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"सेवाहरूलाई सक्षम गर्नुहोस्"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"सिफारिस गरिएका सेवाहरू"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"असक्षम गरिएका सेवाहरू"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"सबै सेवाहरू"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"प्रिन्ट गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"रद्द गरिँदै <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिन्टर त्रुटि <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index eef9880..4afdb86 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Meer informatie over deze printer"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Sommige afdrukservices zijn uitgeschakeld."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Afdrukservice kiezen"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Sommige afdrukservices zijn uitgeschakeld"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printers zoeken"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Geen afdrukservices ingeschakeld"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Geen printers gevonden"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Kan geen printers toevoegen"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Selecteer om printer toe te voegen"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Selecteer om in te schakelen"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Ingeschakelde services"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Aanbevolen services"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Uitgeschakelde services"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Alle services"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> afdrukken"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> annuleren"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printerfout <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pa-rIN/strings.xml b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
index 7d7860c..1886ef5 100644
--- a/packages/PrintSpooler/res/values-pa-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"ਇਸ ਪ੍ਰਿੰਟਰ ਬਾਰੇ ਹੋਰ ਜਾਣਕਾਰੀ"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"ਕੁਝ ਪ੍ਰਿੰਟ ਸੇਵਾਵਾਂ ਅਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਹਨ।"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"ਪ੍ਰਿੰਟ ਸੇਵਾ ਚੁਣੋ"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"ਕੁਝ ਪ੍ਰਿੰਟ ਸੇਵਾਵਾਂ ਅਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਹਨ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ਪ੍ਰਿੰਟਰ ਖੋਜ ਰਿਹਾ ਹੈ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ਪ੍ਰਿੰਟ ਸੇਵਾਵਾਂ ਯੋਗ ਨਹੀਂ ਬਣਾਈਆਂ ਗਈਆਂ"</string>
<string name="print_no_printers" msgid="4869403323900054866">"ਕੋਈ ਪ੍ਰਿੰਟਰ ਨਹੀਂ ਮਿਲੇ"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"ਪ੍ਰਿੰਟਰ ਸ਼ਾਮਲ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"ਪ੍ਰਿੰਟਰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਚੁਣੋ"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"ਯੋਗ ਬਣਾਉਣ ਲਈ ਚੁਣੋ"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"ਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਸੇਵਾਵਾਂ"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀਆਂ ਸੇਵਾਵਾਂ"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"ਅਯੋਗ ਬਣਾਈਆਂ ਗਈਆਂ ਸੇਵਾਵਾਂ"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"ਸਾਰੀਆਂ ਸੇਵਾਵਾਂ"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਿੰਟ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ਨੂੰ ਰੱਦ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ਪ੍ਰਿੰਟਰ ਅਸ਼ੁੱਧੀ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 6837edf..45649bb 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -63,11 +63,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Więcej informacji o tej drukarce"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Niektóre usługi drukowania są wyłączone."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Wybierz usługę drukowania"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Niektóre usługi drukowania są wyłączone"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Szukanie drukarek"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Brak włączonych usług drukowania"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nie znaleziono drukarek"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Nie można dodawać drukarek"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Wybierz, by dodać drukarkę"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Wybierz, by włączyć usługę"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Włączone usługi"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Polecane usługi"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Wyłączone usługi"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Wszystkie usługi"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Drukowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Anulowanie: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Błąd drukarki: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index c9713c9..58eb24f 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Mais informações sobre essa impressora"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Alguns serviços de impressão estão desativados."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Selecione o serviço de impressão"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alguns serviços de impressão estão desativados"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nenhuma impressora encontrada"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Não é possível adicionar impressoras"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Selecione para adicionar uma impressora"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Selecione para ativar"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Serviços ativados"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 9fabc0f..370bbb9 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Mais informações acerca desta impressora"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Alguns serviços de impressão estão desativados."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Escolher o serviço de impressão"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alguns serviços de impressão estão desativados"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"A procurar impressoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nenhuma impressora encontrada"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Não é possível adicionar impressoras"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Selecione para adicionar uma impressora"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Selecione para ativar"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Serviços ativados"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"A imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"A cancelar <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro da impressora <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index c9713c9..58eb24f 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Mais informações sobre essa impressora"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Alguns serviços de impressão estão desativados."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Selecione o serviço de impressão"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Alguns serviços de impressão estão desativados"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nenhuma impressora encontrada"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Não é possível adicionar impressoras"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Selecione para adicionar uma impressora"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Selecione para ativar"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Serviços ativados"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Serviços recomendados"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Serviços desativados"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Todos os serviços"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Imprimindo <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Cancelando <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Erro ao imprimir <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 7364eb0..1097d56 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -62,11 +62,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Mai multe informații despre această imprimantă"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Unele servicii de printare sunt dezactivate."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Alegeți serviciul de printare"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Unele servicii de printare sunt dezactivate"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Se caută imprimante"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Niciun serviciu de printare activat"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nu au fost găsite imprimante"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Nu pot fi adăugate imprimante"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Selectați pentru a adăuga o imprimantă"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Selectați pentru a activa"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Servicii activate"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Servicii recomandate"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Servicii dezactivate"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Toate serviciile"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Se printează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Se anulează <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Eroare de printare: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index d3d0d3f..24b1e0d 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -63,11 +63,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Подробные сведения о принтере"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Некоторые службы печати отключены."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Выберите службу печати"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Некоторые службы печати отключены"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Поиск принтеров…"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Службы печати недоступны"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Ничего не найдено"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Невозможно добавить принтеры"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Выберите, чтобы добавить принтер"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Выберите, чтобы включить"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Включенные службы"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Рекомендуемые службы"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Отключенные службы"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Все службы печати"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Печать задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\"…"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отмена задания <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>…"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Ошибка задания \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index 610442d..707c151 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"මෙම මුද්රණ යන්ත්රය ගැන තවත් තොරතුරු"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"සමහර මුද්රණ සේවා අබලයි."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"මුද්රණ සේවාව තෝරන්න"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"සමහර මුද්රණ සේවා අබලයි"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"මුද්රණ යන්ත්ර සොයමින්"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"මුද්රණ සේවා සබල නැත"</string>
<string name="print_no_printers" msgid="4869403323900054866">"මුද්රණ යන්ත්ර සොයා නොගැනුණි"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"මුද්රණ යන්ත්ර එක් කළ නොහැකිය"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"මුද්රණ යන්ත්රය එක් කිරීමට තෝරන්න"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"සබල කිරීමට තෝරන්න"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"සබල කළ සේවා"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"නිර්දේශිත සේවා"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"අබල කළ සේවා"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"සියලු සේවා"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> මුද්රණය වේ"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"අවලංගු කෙරේ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"මුද්රණ දෝෂය <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 603d1d2..1f13b54 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -63,11 +63,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Ďalšie informácie o tejto tlačiarni"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Niektoré tlačové služby sú vypnuté."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Výber tlačovej služby"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Niektoré tlačové služby sú zakázané"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhľadávanie tlačiarní"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Žiadne tlačové služby nie sú aktivované"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nenašli sa žiadne tlačiarne"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Nie je možné pridať tlačiarne"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Výber služby na pridanie tlačiarne"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Vyberte a povoľte"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Povolené služby"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Odporúčané služby"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Zakázané služby"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Všetky služby"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Prebieha tlač úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Prebieha zrušenie úlohy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Chyba tlačiarne – úloha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index 4a08269..3f8a5e6 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -63,11 +63,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Več informacij o tem tiskalniku"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Nekatere tiskalne storitve so onemogočene."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Izberite tiskalno storitev"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Nekatere tiskalne storitve so onemogočene"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Iskanje tiskalnikov"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ni omogočenih tiskalnih storitev"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Tiskalnikov ni mogoče najti"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Tiskalnikov ni mogoče dodati"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Izberite za dodajanje tiskalnika"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Izberite, če želite omogočiti"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Omogočene storitve"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Priporočene storitve"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Onemogočene storitve"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Vse storitve"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Tiskanje: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Preklic: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Napaka tiskalnika: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
index b0902ef..0b843d7 100644
--- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml
+++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Më shumë informacione mbi këtë printer"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Disa shërbime printimi janë çaktivizuar."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Zgjidh shërbimin e printimit"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Disa shërbime printimi janë çaktivizuar"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Po kërkon për printerë"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nuk ka shërbime printimi të aktivizuara"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Nuk u gjet asnjë printer"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Nuk mund të shtohen printerë"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Zgjidh për të shtuar printer"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Zgjidh për të aktivizuar"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Shërbimet e aktivizuara"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Shërbimet e rekomanduara"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Shërbimet e çaktivizuara"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Të gjitha shërbimet"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Po printon <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Po anulon <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri ndeshi në gabim gjatë punës: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index feb2940..8baa23c 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -62,11 +62,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Још информација о овом штампачу"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Неке услуге штампања су онемогућене."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Изаберите услугу штампања"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Неке услуге штампања су онемогућене"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Претрага штампача"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ниједна услуга штампања није омогућена"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Није пронађен ниједан штампач"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Није могуће додати штампаче"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Изаберите да бисте додали штампач"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Изаберите да бисте омогућили"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Омогућене услуге"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Препоручене услуге"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Онемогућене услуге"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Све услуге"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Штампа се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Отказује се <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Грешка штампача <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index cf398c7..64b6b20 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Mer information om den här skrivaren"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Några utskriftstjänster har inaktiverats."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Välj utskriftstjänst"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Några utskriftstjänster har inaktiverats"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Söker efter skrivare"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Inga utskriftstjänster har aktiverats"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Det gick inte att hitta några skrivare"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Det går inte att lägga till skrivare"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Lägg till en skrivare"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Välj om du vill aktivera"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Aktiverade tjänster"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Rekommenderade tjänster"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Inaktiverade tjänster"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Alla tjänster"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Skriver ut <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Avbryter <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Skrivarfel för <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index 7e00b70..b3ffa71 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Maelezo zaidi kuhusu printa hii"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Baadhi ya huduma za uchapishaji zimezimwa."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Chagua huduma ya printa"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Baadhi ya huduma za uchapishaji haziruhusiwi"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Inatafuta printa"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Huduma za kuchapisha hazijawashwa"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Hakuna printa zilizopatikana"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Haiwezi kuongeza printa"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Chagua printa ya kuongeza"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Chagua ili uruhusu"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Huduma zinazoruhusiwa"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Huduma zinazopendekezwa"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Huduma ambazo haziruhusiwi"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Huduma zote"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Inachapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Inaghairi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Hitilafu ya kuchapisha <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index ae0b774..7ae3cbc 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"இந்தப் பிரிண்டர் பற்றிய கூடுதல் தகவல்"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"சில அச்சுப் பொறிகள் முடக்கப்பட்டன."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"அச்சுப் பொறியைத் தேர்வுசெய்யவும்"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"சில அச்சுப் பொறிகள் முடக்கப்பட்டன"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"அச்சுப்பொறிகளைத் தேடுகிறது"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"அச்சுப் பொறிகள் இல்லை"</string>
<string name="print_no_printers" msgid="4869403323900054866">"பிரிண்டர்கள் எதுவுமில்லை"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"பிரிண்டர்களைச் சேர்க்க முடியவில்லை"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"பிரிண்டரைச் சேர்க்க, தேர்ந்தெடுக்கவும்"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"இயக்குவதற்குத் தேர்ந்தெடுக்கவும்"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"இயக்கப்பட்ட அச்சுப் பொறிகள்"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"பரிந்துரைக்கப்படும் அச்சுப் பொறிகள்"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"முடக்கப்பட்ட அச்சுப் பொறிகள்"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"எல்லா அச்சுப் பொறிகளும்"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ அச்சிடுகிறது"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ஐ ரத்துசெய்கிறது"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"பிரிண்டர் பிழை <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index 5fd8d60..9e8dea2 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"ఈ ప్రింటర్ గురించి మరింత సమాచారం"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"కొన్ని ముద్రణ సేవలు నిలిపివేయబడ్డాయి."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"ముద్రణ సేవను ఎంచుకోండి"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"కొన్ని ముద్రణ సేవలు నిలిపివేయబడ్డాయి"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ప్రింటర్ల కోసం శోధిస్తోంది"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ముద్రణ సేవలు ఏవీ ప్రారంభించలేదు"</string>
<string name="print_no_printers" msgid="4869403323900054866">"ప్రింటర్లు కనుగొనబడలేదు"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"ప్రింటర్లను జోడించడం సాధ్యపడలేదు"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"ప్రింటర్ను జోడించడానికి ఎంచుకోండి"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"ప్రారంభించడానికి ఎంచుకోండి"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"ప్రారంభించిన సేవలు"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"సిఫార్సు చేయబడిన సేవలు"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"నిలిపివేసిన సేవలు"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"అన్ని సేవలు"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను ముద్రిస్తోంది"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>ను రద్దు చేస్తోంది"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ప్రింటర్ లోపం <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index ebd5e2a..c623dd7 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"ข้อมูลเพิ่มเติมเกี่ยวกับเครื่องพิมพ์นี้"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"บริการพิมพ์บางอย่างถูกปิดใช้"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"เลือกบริการพิมพ์"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"บริการพิมพ์บางอย่างปิดใช้อยู่"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"กำลังค้นหาเครื่องพิมพ์"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ไม่ได้เปิดใช้บริการพิมพ์"</string>
<string name="print_no_printers" msgid="4869403323900054866">"ไม่พบเครื่องพิมพ์"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"เพิ่มเครื่องพิมพ์ไม่ได้"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"เลือกเพื่อเพิ่มเครื่องพิมพ์"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"เลือกเพื่อเปิดใช้"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"บริการที่เปิดใช้"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"บริการที่แนะนำ"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"บริการที่ปิดใช้"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"บริการทั้งหมด"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"กำลังพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"กำลังยกเลิก <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"ข้อผิดพลาดเครื่องพิมพ์ <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index ebe869b..0494cf6 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Higit pang impormasyon tungkol sa printer na ito"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Naka-disable ang ilang serbisyo sa pag-print."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Pumili ng serbisyo ng pag-print"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Naka-disable ang ilang serbisyo sa pag-print"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Naghahanap ng mga printer"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Walang mga naka-enable na serbisyo sa pag-print"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Walang mga printer na nakita"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Hindi makapagdagdag ng mga printer"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Piliin upang magdagdag ng printer"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Piliin upang i-enable"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Mga naka-enable na serbisyo"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Mga inirerekomendang serbisyo"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Mga naka-disable na serbisyo"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Lahat ng serbisyo"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Pini-print ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Kinakansela ang <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Error sa printer <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index 9cd42ab..2818f36 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Bu yazıcıyla ilgili daha fazla bilgi"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Bazı yazdırma hizmetleri devre dışı."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Yazdırma hizmetini seçin"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Bazı yazdırma hizmetleri devre dışı bırakıldı"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Yazıcılar aranıyor"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Etkin yazıcı hizmeti yok"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Yazıcı bulunamadı"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Yazıcı eklenemiyor"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Yazıcı eklemek için seçin"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Etkinleştirmek için seçin"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Etkin hizmetler"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Önerilen hizmetler"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Devre dışı bırakılmış hizmetler"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Tüm hizmetler"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> yazdırılıyor"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> iptal ediliyor"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Yazıcı hatası: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 1082147..41051af 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -63,11 +63,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Докладніше про цей принтер"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Деякі служби друку вимкнено."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Вибрати службу друку"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Деякі служби друку вимкнено"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Пошук принтерів"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Немає служб друку"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Принтери не знайдено"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Не можна додати принтери"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Виберіть, щоб додати принтер"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Виберіть, щоб увімкнути"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Увімкнені служби"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Рекомендовані служби"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Вимкнені служби"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Усі служби"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" друкується"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\" скасовується"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Помилка завдання \"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>\""</string>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index 56f1093..a94b16f 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"اس پرنٹر کے بارے میں مزید معلومات"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"پرنٹ کی کچھ سروسز غیر فعال ہیں۔"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"پرنٹ سروس منتخب کریں"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"پرنٹ کی کچھ سروسز غیر فعال ہیں"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"پرنٹرز تلاش کر رہا ہے"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"کوئی پرنٹ سروس فعال نہیں"</string>
<string name="print_no_printers" msgid="4869403323900054866">"کوئی پرنٹرز نہيں ملے"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"پرنٹرز شامل نہیں ہو سکتے"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"پرنٹر شامل کرنے کیلئے منتخب کریں"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"فعال کرنے کیلئے منتخب کریں"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"فعال کردہ سروسز"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"تجویز کردہ سروسز"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"غیر فعال کردہ سروسز"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"تمام سروسز"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> پرنٹ کررہا ہے"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> کو منسوخ کر رہا ہے"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"پرنٹر کی خرابی <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index 30b218e..ee6266f 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Printer haqida batafsil ma’lumot"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Bir qancha chop etish xizmatlari o‘chirilgan."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Chop etish xizmatini tanlang"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Bir qancha chop etish xizmatlari o‘chirilgan"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printerlar qidirilmoqda"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Hech qaysi chop etish xizmati yoqilmagan"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Printerlar topilmadi"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Printerlarni qo‘shib bo‘lmaydi"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Printer qo‘shish uchun tanlang"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Yoqish uchun tanlang"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Yoqilgan xizmatlar"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Tavsiya etilgan xizmatlar"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"O‘chirilgan xizmatlar"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Barcha xizmatlar"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Chop etilmoqda: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> bekor qilinmoqda"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Printerda xatolik: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index 32aaf63..df9e1a4 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Thông tin khác về máy in này"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Một số dịch vụ in bị vô hiệu hóa."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Chọn dịch vụ in"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Một số dịch vụ in đã bị tắt"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Đang tìm kiếm máy in"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Chưa kích hoạt dịch vụ in nào"</string>
<string name="print_no_printers" msgid="4869403323900054866">"Không tìm thấy máy in"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Không thể thêm máy in"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Chọn để thêm máy in"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Chọn để bật"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Dịch vụ đã bật"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Dịch vụ được đề xuất"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Dịch vụ đã tắt"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Tất cả dịch vụ"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"In <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Hủy <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Lỗi máy in <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 42cf3b1..4a27839 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -61,11 +61,25 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"关于此打印机的更多信息"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"部分打印服务已停用。"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"选择打印服务"</string>
+ <!-- no translation found for print_services_disabled_toast (9089060734685174685) -->
+ <skip />
<string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"未启用任何打印服务"</string>
<string name="print_no_printers" msgid="4869403323900054866">"找不到打印机"</string>
+ <!-- no translation found for cannot_add_printer (7840348733668023106) -->
+ <skip />
+ <!-- no translation found for select_to_add_printers (3800709038689830974) -->
+ <skip />
+ <!-- no translation found for enable_print_service (3482815747043533842) -->
+ <skip />
+ <!-- no translation found for enabled_services_title (7036986099096582296) -->
+ <skip />
+ <!-- no translation found for recommended_services_title (3799434882937956924) -->
+ <skip />
+ <!-- no translation found for disabled_services_title (7313253167968363211) -->
+ <skip />
+ <!-- no translation found for all_services_title (5578662754874906455) -->
+ <skip />
<string name="printing_notification_title_template" msgid="295903957762447362">"正在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"打印机在打印“<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>”时出错"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 0a458ad..f7c8fc9 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"此打印機詳情"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"已停用部分列印服務。"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"部分列印服務已停用"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋打印機"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"沒有已啟用的列印服務"</string>
<string name="print_no_printers" msgid="4869403323900054866">"找不到打印機"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"無法新增印表機"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"選擇即可新增印表機"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"選取即可啟用"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"已啟用的服務"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"推薦服務"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"已停用的服務"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"所有服務"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"正在列印 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"打印機錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 7a30011..aa18f3c 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"查看這台印表機的詳細資訊"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"部分列印服務已停用。"</string>
- <string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"已停用部分列印服務"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋印表機"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"未啟用任何列印服務"</string>
<string name="print_no_printers" msgid="4869403323900054866">"找不到印表機"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"無法新增印表機"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"選取即可新增印表機"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"選取即可啟用"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"已啟用的列印服務"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"建議的列印服務"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"已停用的列印服務"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"所有列印服務"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"正在列印 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"正在取消 <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"印表機發生錯誤:<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index f57b58c..9cfcb33 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -61,11 +61,17 @@
</plurals>
<string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="printer_info_desc" msgid="7181988788991581654">"Olunye ulwazi mayelana nale phrinta"</string>
- <string name="print_services_disabled_toast" msgid="1205302482388937547">"Amanye amasevisi wokuphrinta akhutshaziwe."</string>
- <string name="choose_print_service" msgid="3740309762324459694">"Khetha isevisi yephrinta"</string>
+ <string name="print_services_disabled_toast" msgid="9089060734685174685">"Amanye amasevisi okuphrinta akhutshaziwe"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Isesha amaphrinta"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Amasevisi ephrinta akavuliwe."</string>
<string name="print_no_printers" msgid="4869403323900054866">"Awekho amaphrinta atholiwe"</string>
+ <string name="cannot_add_printer" msgid="7840348733668023106">"Ayikwazi ukungeza amaphrinta"</string>
+ <string name="select_to_add_printers" msgid="3800709038689830974">"Khetha ukuze ungeze iphrinta"</string>
+ <string name="enable_print_service" msgid="3482815747043533842">"Khetha ukuze unike amandla"</string>
+ <string name="enabled_services_title" msgid="7036986099096582296">"Amasevisi anikwe amandla"</string>
+ <string name="recommended_services_title" msgid="3799434882937956924">"Amasevisi anconyiwe"</string>
+ <string name="disabled_services_title" msgid="7313253167968363211">"Amasevisi akhutshaziwe"</string>
+ <string name="all_services_title" msgid="5578662754874906455">"Onke amasevisi"</string>
<string name="printing_notification_title_template" msgid="295903957762447362">"Iphrinta i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="cancelling_notification_title_template" msgid="1821759594704703197">"Ikhansela i-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"Iphutha lephrinta ye-<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/layout/restricted_icon.xml b/packages/SettingsLib/res/layout/restricted_icon.xml
index d57fb80..724a524 100644
--- a/packages/SettingsLib/res/layout/restricted_icon.xml
+++ b/packages/SettingsLib/res/layout/restricted_icon.xml
@@ -17,5 +17,4 @@
android:id="@+id/restricted_icon"
android:layout_width="@dimen/restricted_icon_size"
android:layout_height="@dimen/restricted_icon_size"
- android:src="@drawable/ic_info"
- android:gravity="end|center_vertical" />
\ No newline at end of file
+ android:src="@drawable/ic_info" />
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/usage_view.xml b/packages/SettingsLib/res/layout/usage_view.xml
index 28981f8..aa1a046 100644
--- a/packages/SettingsLib/res/layout/usage_view.xml
+++ b/packages/SettingsLib/res/layout/usage_view.xml
@@ -22,7 +22,8 @@
<LinearLayout
android:id="@+id/graph_label_group"
android:layout_width="match_parent"
- android:layout_height="@dimen/usage_graph_area_height"
+ android:layout_height="0dp"
+ android:layout_weight="1"
android:orientation="horizontal"
android:clipChildren="false"
android:clipToPadding="false">
@@ -37,6 +38,7 @@
layout="@layout/usage_side_label" />
<Space
+ android:id="@+id/space1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
@@ -45,6 +47,7 @@
layout="@layout/usage_side_label" />
<Space
+ android:id="@+id/space2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index ef397f6..1b49eed 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -775,7 +775,7 @@
<!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
<string name="enabled_by_admin">Enabled by administrator</string>
- <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
+ <!-- Summary for switch preference to denote it is switched off [CHAR LIMIT=50] -->
<string name="disabled_by_admin">Disabled by administrator</string>
<!-- Option in navigation drawer that leads to Settings main screen [CHAR LIMIT=30] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java
deleted file mode 100644
index 4c0450e..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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.settingslib;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.support.v7.preference.DropDownPreference;
-import android.support.v7.preference.PreferenceViewHolder;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.ArrayAdapter;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
-public class RestrictedDropDownPreference extends DropDownPreference {
- private Spinner mSpinner;
- private final Drawable mRestrictedPadlock;
- private final int mRestrictedPadlockPadding;
- private List<RestrictedItem> mRestrictedItems = new ArrayList<>();
-
- public RestrictedDropDownPreference(Context context) {
- this(context, null);
- }
-
- public RestrictedDropDownPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(context);
- mRestrictedPadlockPadding = context.getResources().getDimensionPixelSize(
- R.dimen.restricted_icon_padding);
- }
-
- private final OnItemSelectedListener mItemSelectedListener = new OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
- if (position >= 0) {
- String value = getEntryValues()[position].toString();
- RestrictedItem item = getRestrictedItemForEntryValue(value);
- if (item != null) {
- RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
- item.enforcedAdmin);
- mSpinner.setSelection(findIndexOfValue(getValue()));
- } else if (!value.equals(getValue()) && callChangeListener(value)) {
- setValue(value);
- }
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- // noop
- }
- };
-
- @Override
- protected ArrayAdapter createAdapter() {
- return new RestrictedArrayItemAdapter(getContext());
- }
-
- @Override
- public void setValue(String value) {
- if (getRestrictedItemForEntryValue(value) != null) {
- return;
- }
- super.setValue(value);
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder view) {
- super.onBindViewHolder(view);
- mSpinner = (Spinner) view.itemView.findViewById(R.id.spinner);
- mSpinner.setOnItemSelectedListener(mItemSelectedListener);
- }
-
- private class RestrictedArrayItemAdapter extends ArrayAdapter<String> {
- public RestrictedArrayItemAdapter(Context context) {
- super(context, R.layout.spinner_dropdown_restricted_item);
- }
-
- @Override
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
- TextView view = (TextView) super.getView(position, convertView, parent);
- CharSequence entry = getItem(position);
- boolean isEntryRestricted = isRestrictedForEntry(entry);
- RestrictedLockUtils.setTextViewPadlock(getContext(), view, isEntryRestricted);
- view.setEnabled(!isEntryRestricted);
- return view;
- }
- }
-
- private boolean isRestrictedForEntry(CharSequence entry) {
- if (entry == null) {
- return false;
- }
- for (RestrictedItem item : mRestrictedItems) {
- if (entry.equals(item.entry)) {
- return true;
- }
- }
- return false;
- }
-
- private RestrictedItem getRestrictedItemForEntryValue(CharSequence entryValue) {
- if (entryValue == null) {
- return null;
- }
- for (RestrictedItem item : mRestrictedItems) {
- if (entryValue.equals(item.entryValue)) {
- return item;
- }
- }
- return null;
- }
-
- public void addRestrictedItem(RestrictedItem item) {
- mRestrictedItems.add(item);
- }
-
- public static class RestrictedItem {
- public CharSequence entry;
- public CharSequence entryValue;
- public EnforcedAdmin enforcedAdmin;
-
- public RestrictedItem(CharSequence entry, CharSequence entryValue,
- EnforcedAdmin enforcedAdmin) {
- this.entry = entry;
- this.entryValue = entryValue;
- this.enforcedAdmin = enforcedAdmin;
- }
- }
-}
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 0c0af24..47023c1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -22,9 +22,6 @@
import android.os.UserHandle;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
-import android.text.Spanned;
-import android.text.SpannableStringBuilder;
-import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
@@ -39,8 +36,6 @@
public class RestrictedPreferenceHelper {
private final Context mContext;
private final Preference mPreference;
- private final Drawable mRestrictedPadlock;
- private final int mRestrictedPadlockPadding;
private boolean mDisabledByAdmin;
private EnforcedAdmin mEnforcedAdmin;
@@ -52,10 +47,6 @@
mContext = context;
mPreference = preference;
- mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
- mRestrictedPadlockPadding = mContext.getResources().getDimensionPixelSize(
- R.dimen.restricted_icon_padding);
-
if (attrs != null) {
final TypedArray attributes = context.obtainStyledAttributes(attrs,
R.styleable.RestrictedPreference);
@@ -154,10 +145,10 @@
*/
public boolean setDisabledByAdmin(EnforcedAdmin admin) {
final boolean disabled = (admin != null ? true : false);
- mEnforcedAdmin = (disabled ? admin : null);
+ mEnforcedAdmin = admin;
+ mPreference.setEnabled(!disabled);
if (mDisabledByAdmin != disabled) {
mDisabledByAdmin = disabled;
- mPreference.setEnabled(!disabled);
return true;
}
return false;
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java b/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java
index 530ec16..1fff0fb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/UsageGraph.java
@@ -43,6 +43,7 @@
private final Paint mDottedPaint;
private final Drawable mDivider;
+ private final Drawable mTintedDivider;
private final int mDividerSize;
private final Path mPath = new Path();
@@ -51,6 +52,7 @@
private final SparseIntArray mPaths = new SparseIntArray();
// Paths in local coordinates for drawing.
private final SparseIntArray mLocalPaths = new SparseIntArray();
+ private final int mCornerRadius;
private int mAccentColor;
private boolean mShowProjection;
@@ -59,6 +61,10 @@
private float mMaxX = 100;
private float mMaxY = 100;
+ private float mMiddleDividerLoc = .5f;
+ private int mMiddleDividerTint = -1;
+ private int mTopDividerTint = -1;
+
public UsageGraph(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
final Resources resources = context.getResources();
@@ -68,8 +74,8 @@
mLinePaint.setStrokeCap(Cap.ROUND);
mLinePaint.setStrokeJoin(Join.ROUND);
mLinePaint.setAntiAlias(true);
- mLinePaint.setPathEffect(new CornerPathEffect(resources.getDimensionPixelSize(
- R.dimen.usage_graph_line_corner_radius)));
+ mCornerRadius = resources.getDimensionPixelSize(R.dimen.usage_graph_line_corner_radius);
+ mLinePaint.setPathEffect(new CornerPathEffect(mCornerRadius));
mLinePaint.setStrokeWidth(resources.getDimensionPixelSize(R.dimen.usage_graph_line_width));
mFillPaint = new Paint(mLinePaint);
@@ -86,6 +92,7 @@
TypedValue v = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.listDivider, v, true);
mDivider = context.getDrawable(v.resourceId);
+ mTintedDivider = context.getDrawable(v.resourceId);
mDividerSize = resources.getDimensionPixelSize(R.dimen.usage_graph_divider_size);
}
@@ -98,6 +105,15 @@
mMaxY = maxY;
}
+ void setDividerLoc(int height) {
+ mMiddleDividerLoc = 1 - height / mMaxY;
+ }
+
+ void setDividerColors(int middleColor, int topColor) {
+ mMiddleDividerTint = middleColor;
+ mTopDividerTint = topColor;
+ }
+
public void addPath(SparseIntArray points) {
for (int i = 0; i < points.size(); i++) {
mPaths.put(points.keyAt(i), points.valueAt(i));
@@ -150,7 +166,7 @@
if (mLocalPaths.size() > 0) {
int lastX = mLocalPaths.keyAt(mLocalPaths.size() - 1);
int lastY = mLocalPaths.valueAt(mLocalPaths.size() - 1);
- if (lastY != PATH_DELIM && (lastX == lx || lastY == ly)) {
+ if (lastY != PATH_DELIM && !hasDiff(lastX, lx) && !hasDiff(lastY, ly)) {
pendingYLoc = ly;
continue;
}
@@ -160,6 +176,10 @@
}
}
+ private boolean hasDiff(int x1, int x2) {
+ return Math.abs(x2 - x1) >= mCornerRadius;
+ }
+
private int getX(float x) {
return (int) (x / mMaxX * getWidth());
}
@@ -180,9 +200,12 @@
@Override
protected void onDraw(Canvas canvas) {
// Draw lines across the top, middle, and bottom.
- drawDivider(0, canvas);
- drawDivider((canvas.getHeight() - mDividerSize) / 2, canvas);
- drawDivider(canvas.getHeight() - mDividerSize, canvas);
+ if (mMiddleDividerLoc != 0) {
+ drawDivider(0, canvas, mTopDividerTint);
+ }
+ drawDivider((int) ((canvas.getHeight() - mDividerSize) * mMiddleDividerLoc), canvas,
+ mMiddleDividerTint);
+ drawDivider(canvas.getHeight() - mDividerSize, canvas, -1);
if (mLocalPaths.size() == 0) {
return;
@@ -242,8 +265,13 @@
canvas.drawPath(mPath, mFillPaint);
}
- private void drawDivider(int y, Canvas canvas) {
- mDivider.setBounds(0, y, canvas.getWidth(), y + mDividerSize);
- mDivider.draw(canvas);
+ private void drawDivider(int y, Canvas canvas, int tintColor) {
+ Drawable d = mDivider;
+ if (tintColor != -1) {
+ mTintedDivider.setTint(tintColor);
+ d = mTintedDivider;
+ }
+ d.setBounds(0, y, canvas.getWidth(), y + mDividerSize);
+ d.draw(canvas);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java b/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
index f95a97ad..ee1821d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/UsageView.java
@@ -20,6 +20,7 @@
import android.util.SparseIntArray;
import android.view.Gravity;
import android.view.LayoutInflater;
+import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -98,6 +99,26 @@
mUsageGraph.setAccentColor(color);
}
+ public void setDividerLoc(int dividerLoc) {
+ mUsageGraph.setDividerLoc(dividerLoc);
+ }
+
+ public void setDividerColors(int middleColor, int topColor) {
+ mUsageGraph.setDividerColors(middleColor, topColor);
+ }
+
+ public void setSideLabelWeights(float before, float after) {
+ setWeight(R.id.space1, before);
+ setWeight(R.id.space2, after);
+ }
+
+ private void setWeight(int id, float weight) {
+ View v = findViewById(id);
+ LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) v.getLayoutParams();
+ params.weight = weight;
+ v.setLayoutParams(params);
+ }
+
public void setSideLabels(CharSequence[] labels) {
if (labels.length != mLabels.length) {
throw new IllegalArgumentException("Invalid number of labels");
diff --git a/packages/SettingsProvider/res/values-bs-rBA/defaults.xml b/packages/SettingsProvider/res/values-bs-rBA/defaults.xml
index 5650077..4a87a12 100644
--- a/packages/SettingsProvider/res/values-bs-rBA/defaults.xml
+++ b/packages/SettingsProvider/res/values-bs-rBA/defaults.xml
@@ -19,9 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for def_device_name (6309317409634339402) -->
- <skip />
- <!-- no translation found for def_device_name_simple (9037785625140748221) -->
- <skip />
+ <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string>
+ <string name="def_device_name_simple" msgid="9037785625140748221">"%1$s"</string>
<string name="def_nfc_payment_component" msgid="5861297439873026958"></string>
</resources>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 38ea880..5d90189 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -20,6 +20,8 @@
<string name="bugreport_in_progress_title">Bug report <xliff:g id="id">#%d</xliff:g> is being generated</string>
<!-- Title of notification indicating a bugreport has been successfully captured. [CHAR LIMIT=50] -->
<string name="bugreport_finished_title">Bug report <xliff:g id="id">#%d</xliff:g> captured</string>
+ <!-- Title of notification indicating a bugreport has been successfully captured, but screenshot is not finished yet. [CHAR LIMIT=50] -->
+ <string name="bugreport_finished_pending_screenshot_title">Bug report <xliff:g id="id">#%d</xliff:g> captured but screenshot pending</string>
<!-- Title of notification indicating a bugreport is being updated before it can be shared. [CHAR LIMIT=50] -->
<string name="bugreport_updating_title">Adding details to the bug report</string>
<!-- Content notification indicating a bugreport is being updated before it can be shared, asking the user to wait [CHAR LIMIT=50] -->
@@ -29,7 +31,10 @@
<string name="bugreport_finished_text" product="watch">Swipe left to share your bug report</string>
<!-- Text of notification indicating that tapping will share the captured bugreport. [CHAR LIMIT=100] -->
<string name="bugreport_finished_text" product="default">Tap to share your bug report</string>
-
+ <!-- Text of notification indicating that swipe left will share the captured bugreport, but giving user the option to wait for the screenshot. [CHAR LIMIT=100] -->
+ <string name="bugreport_finished_pending_screenshot_text" product="watch">Tap to share your bug report without a screenshot or wait for the screenshot to finish</string>
+ <!-- Text of notification indicating that tapping will share the captured bugreport, but giving user the option to wait for the screenshot. [CHAR LIMIT=100] -->
+ <string name="bugreport_finished_pending_screenshot_text" product="default">Tap to share your bug report without a screenshot or wait for the screenshot to finish</string>
<!-- Body of dialog informing user about contents of a bugreport. [CHAR LIMIT=NONE] -->
<string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people you trust.</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 1c6a071..d212d53 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -714,7 +714,7 @@
if (info.finished) {
Log.d(TAG, "Screenshot finished after bugreport; updating share notification");
info.renameScreenshots(mScreenshotsDir);
- sendBugreportNotification(mContext, info);
+ sendBugreportNotification(mContext, info, mTakingScreenshot);
}
msg = mContext.getString(R.string.bugreport_screenshot_taken);
} else {
@@ -803,10 +803,10 @@
boolean isPlainText = info.bugreportFile.getName().toLowerCase().endsWith(".txt");
if (!isPlainText) {
// Already zipped, send it right away.
- sendBugreportNotification(context, info);
+ sendBugreportNotification(context, info, mTakingScreenshot);
} else {
// Asynchronously zip the file first, then send it.
- sendZippedBugreportNotification(context, info);
+ sendZippedBugreportNotification(context, info, mTakingScreenshot);
}
}
@@ -903,7 +903,8 @@
/**
* Sends a notification indicating the bugreport has finished so use can share it.
*/
- private static void sendBugreportNotification(Context context, BugreportInfo info) {
+ private static void sendBugreportNotification(Context context, BugreportInfo info,
+ boolean takingScreenshot) {
// Since adding the details can take a while, do it before notifying user.
addDetailsToZipFile(context, info);
@@ -914,12 +915,20 @@
shareIntent.putExtra(EXTRA_ID, info.id);
shareIntent.putExtra(EXTRA_INFO, info);
- final String title = context.getString(R.string.bugreport_finished_title, info.id);
+ final String title, content;
+ if (takingScreenshot) {
+ title = context.getString(R.string.bugreport_finished_pending_screenshot_title,
+ info.id);
+ content = context.getString(R.string.bugreport_finished_pending_screenshot_text);
+ } else {
+ title = context.getString(R.string.bugreport_finished_title, info.id);
+ content = context.getString(R.string.bugreport_finished_text);
+ }
final Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setContentTitle(title)
.setTicker(title)
- .setContentText(context.getString(R.string.bugreport_finished_text))
+ .setContentText(content)
.setContentIntent(PendingIntent.getService(context, info.id, shareIntent,
PendingIntent.FLAG_UPDATE_CURRENT))
.setDeleteIntent(newCancelIntent(context, info))
@@ -958,12 +967,12 @@
* Sends a zipped bugreport notification.
*/
private static void sendZippedBugreportNotification(final Context context,
- final BugreportInfo info) {
+ final BugreportInfo info, final boolean takingScreenshot) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
zipBugreport(info);
- sendBugreportNotification(context, info);
+ sendBugreportNotification(context, info, takingScreenshot);
return null;
}
}.execute();
@@ -1181,14 +1190,13 @@
* Takes a screenshot and save it to the given location.
*/
private static boolean takeScreenshot(Context context, String screenshotFile) {
- ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE))
- .vibrate(150);
final ProcessBuilder screencap = new ProcessBuilder()
.command("/system/bin/screencap", "-p", screenshotFile);
Log.d(TAG, "Taking screenshot using " + screencap.command());
try {
final int exitValue = screencap.start().waitFor();
if (exitValue == 0) {
+ ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(150);
return true;
}
Log.e(TAG, "screencap (" + screencap.command() + ") failed: " + exitValue);
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index a629aac..47e3b3b 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -130,6 +130,9 @@
private static final boolean RENAMED_SCREENSHOTS = true;
private static final boolean DIDNT_RENAME_SCREENSHOTS = false;
+ private static final boolean PENDING_SCREENSHOT = true;
+ private static final boolean NOT_PENDING_SCREENSHOT = false;
+
private String mDescription;
private String mPlainTextPath;
@@ -409,9 +412,8 @@
sendBugreportStarted(ID2, PID2, NAME2, 1000);
- Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE,
- NEW_NAME, TITLE, DESCRIPTION, 1, RENAMED_SCREENSHOTS);
+ sendBugreportFinished(ID, mZipPath, mScreenshotPath);
+ Bundle extras = acceptBugreportAndGetSharedIntent(ID, PENDING_SCREENSHOT);
detailsUi = new DetailsUi(mUiBot, ID2);
detailsUi.assertName(NAME2);
@@ -602,7 +604,7 @@
private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath,
String screenshotPath) {
sendBugreportFinished(id, bugreportPath, screenshotPath);
- return acceptBugreportAndGetSharedIntent(id);
+ return acceptBugreportAndGetSharedIntent(id, NOT_PENDING_SCREENSHOT);
}
/**
@@ -611,7 +613,11 @@
* @return extras sent in the shared intent.
*/
private Bundle acceptBugreportAndGetSharedIntent(int id) {
- acceptBugreport(id);
+ return acceptBugreportAndGetSharedIntent(id, NOT_PENDING_SCREENSHOT);
+ }
+
+ private Bundle acceptBugreportAndGetSharedIntent(int id, boolean pendingScreenshot) {
+ acceptBugreport(id, pendingScreenshot);
mUiBot.chooseActivity(UI_NAME);
return mListener.getExtras();
}
@@ -627,7 +633,13 @@
* Accepts the notification to share the finished bugreport.
*/
private void acceptBugreport(int id) {
- mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, id));
+ acceptBugreport(id, NOT_PENDING_SCREENSHOT);
+ }
+
+ private void acceptBugreport(int id, boolean pendingScreenshot) {
+ final int res = pendingScreenshot ? R.string.bugreport_finished_pending_screenshot_title
+ : R.string.bugreport_finished_title;
+ mUiBot.clickOnNotification(mContext.getString(res, id));
}
/**
diff --git a/packages/SystemUI/res/layout/battery_detail.xml b/packages/SystemUI/res/layout/battery_detail.xml
index 99121a9..af3e379 100644
--- a/packages/SystemUI/res/layout/battery_detail.xml
+++ b/packages/SystemUI/res/layout/battery_detail.xml
@@ -33,7 +33,7 @@
<com.android.settingslib.graph.UsageView
android:id="@+id/battery_usage"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="141dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="24dp"
systemui:sideLabels="@array/battery_labels"
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 8b337ea..c1fe1a8 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -33,4 +33,10 @@
android:layout_height="match_parent"
android:src="@android:color/white"
android:visibility="gone" />
+ <com.android.systemui.screenshot.ScreenshotSelectorView
+ android:id="@+id/global_screenshot_selector"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:pointerShape="crosshair"/>
</FrameLayout>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index eaa777b..c7e57de 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -304,8 +304,7 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"prikvačivanje zaslona"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
- <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
- <skip />
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> onemogućena je u sigurnom načinu."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Povijest"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Izbriši"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Ta aplikacija ne podržava više prozora"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index f104703..8fda706 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -506,12 +506,9 @@
<string name="headset" msgid="4534219457597457353">"ヘッドセット"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"ヘッドホンを接続しました"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"ヘッドセットを接続しました"</string>
- <!-- no translation found for data_saver (5037565123367048522) -->
- <skip />
- <!-- no translation found for accessibility_data_saver_on (8454111686783887148) -->
- <skip />
- <!-- no translation found for accessibility_data_saver_off (8841582529453005337) -->
- <skip />
+ <string name="data_saver" msgid="5037565123367048522">"データセーバー"</string>
+ <string name="accessibility_data_saver_on" msgid="8454111686783887148">"データセーバー ON"</string>
+ <string name="accessibility_data_saver_off" msgid="8841582529453005337">"データセーバー OFF"</string>
<string name="switch_bar_on" msgid="1142437840752794229">"ON"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"OFF"</string>
<string name="nav_bar" msgid="1993221402773877607">"ナビゲーション バー"</string>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 26a81c8..585984c 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -22,6 +22,9 @@
<!-- Standard notification gravity -->
<integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
+ <!-- The size of the initial peek area at the bottom of the stack (above the nav bar). -->
+ <dimen name="recents_initial_bottom_peek_size">@dimen/recents_task_bar_height</dimen>
+
<dimen name="docked_divider_handle_width">2dp</dimen>
<dimen name="docked_divider_handle_height">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 3797adc..ad314e3 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -303,8 +303,7 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação de tela"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
- <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
- <skip />
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"O app <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Este app não é compatível com o modo de várias janelas"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 3797adc..ad314e3 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -303,8 +303,7 @@
<string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação de tela"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
- <!-- no translation found for recents_launch_disabled_message (1624523193008871793) -->
- <skip />
+ <string name="recents_launch_disabled_message" msgid="1624523193008871793">"O app <xliff:g id="APP">%s</xliff:g> está desativado no modo de segurança."</string>
<string name="recents_history_button_label" msgid="5153358867807604821">"Histórico"</string>
<string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Limpar"</string>
<string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Este app não é compatível com o modo de várias janelas"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 122413d..a2fa3b9 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -99,6 +99,9 @@
<!-- The top padding for the task stack. -->
<dimen name="recents_stack_top_padding">40dp</dimen>
+ <!-- The size of the initial peek area at the bottom of the stack (above the nav bar). -->
+ <dimen name="recents_initial_bottom_peek_size">100dp</dimen>
+
<!-- The side padding for the task stack. -->
<dimen name="recents_stack_left_right_padding">64dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 12c3a5d..a7546a9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -295,6 +295,9 @@
<!-- The size of the initial peek area at the top of the stack (below the status bar). -->
<dimen name="recents_initial_top_peek_size">8dp</dimen>
+ <!-- The size of the initial peek area at the bottom of the stack (above the nav bar). -->
+ <dimen name="recents_initial_bottom_peek_size">100dp</dimen>
+
<!-- The size of the peek area at the top of the stack (below the status bar). -->
<dimen name="recents_layout_focused_top_peek_size">@dimen/recents_history_button_height</dimen>
@@ -307,6 +310,9 @@
<!-- The padding between freeform workspace tasks -->
<dimen name="recents_freeform_workspace_task_padding">8dp</dimen>
+ <!-- The offsets the tasks animate from when recents is launched while docking -->
+ <dimen name="recents_task_view_launched_while_docking_offset">144dp</dimen>
+
<!-- Space reserved for the cards behind the top card in the bottom stack -->
<dimen name="bottom_stack_peek_amount">12dp</dimen>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index c7fb0ec..b35038d 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -17,26 +17,25 @@
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Picture-in-Picture menu -->
+ <!-- Picture-in-Picture (PIP) menu -->
<eat-comment />
- <!-- Button to close PIP on PIP UI -->
- <string name="pip_close" translatable="false">Close PIP</string>
- <!-- Button to move PIP screen to the fullscreen on PIP UI -->
- <string name="pip_fullscreen" translatable="false">Full screen</string>
- <!-- Button to play the current media on PIP UI -->
- <string name="pip_play" translatable="false">Play</string>
- <!-- Button to pause the current media on PIP UI -->
- <string name="pip_pause" translatable="false">Pause</string>
- <!-- Button to close PIP overlay menu on PIP UI -->
- <string name="pip_cancel" translatable="false">Cancel</string>
- <!-- Overlay text on PIP -->
- <string name="pip_hold_home" translatable="false">Hold <b>HOME</b> to control PIP</string>
- <!-- Picture-in-Picture onboarding screen -->
+ <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=16] -->
+ <string name="pip_close">Close PIP</string>
+ <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=16] -->
+ <string name="pip_fullscreen">Full screen</string>
+ <!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=16] -->
+ <string name="pip_play">Play</string>
+ <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=16] -->
+ <string name="pip_pause">Pause</string>
+ <!-- Overlay text on picture-in-picture (PIP) to indicate that longpress HOME key to control PIP [CHAR LIMIT=25] -->
+ <string name="pip_hold_home">Hold <b>HOME</b> to control PIP</string>
+ <!-- Picture-in-Picture (PIP) onboarding screen -->
<eat-comment />
- <!-- Description for onboarding screen. -->
- <string name="pip_onboarding_description" translatable="false">Press and hold the HOME\nbutton to close or control it</string>
- <!-- Button to close onboarding screen. -->
- <string name="pip_onboarding_button" translatable="false">Got it</string>
+ <!-- Description for picture-in-picture (PIP) onboarding screen to indicate that longpress HOME key to control PIP.
+ Line break is needed as if we have CHAR LIMIT=25. [CHAR LIMIT=NONE] -->
+ <string name="pip_onboarding_description">Press and hold the HOME\nbutton to control PIP</string>
+ <!-- Button to close picture-in-picture (PIP) onboarding screen. -->
+ <string name="pip_onboarding_button">Got it</string>
<!-- Font for Recents -->
<!-- DO NOT TRANSLATE -->
<string name="font_roboto_regular" translatable="false">sans-serif</string>
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
index 86bea87..bad739fd 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
@@ -36,6 +36,11 @@
}
@Override
+ public String getTag() {
+ return "ACC";
+ }
+
+ @Override
public void onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index dba731a..526e5fa 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -54,6 +54,11 @@
}
@Override
+ public String getTag() {
+ return "ANG";
+ }
+
+ @Override
public void onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index 89d20de..cb761a9 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -48,4 +48,6 @@
*/
public void onSensorChanged(SensorEvent event) {
}
+
+ public abstract String getTag();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
index 299d0e3..610e219 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
@@ -25,6 +25,11 @@
}
@Override
+ public String getTag() {
+ return "DIR";
+ }
+
+ @Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
Point firstPoint = stroke.getPoints().get(0);
Point lastPoint = stroke.getPoints().get(stroke.getPoints().size() - 1);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
index 8924694..77fda20 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
@@ -25,6 +25,11 @@
}
@Override
+ public String getTag() {
+ return "DUR";
+ }
+
+ @Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
return DurationCountEvaluator.evaluate(stroke.getDurationSeconds() / stroke.getCount());
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
index 78bc0dd..de8a188 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
@@ -24,6 +24,11 @@
}
@Override
+ public String getTag() {
+ return "END_LNGTH";
+ }
+
+ @Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
return EndPointLengthEvaluator.evaluate(stroke.getEndPointLength());
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
index 652d969..9b6ddc8 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
@@ -26,6 +26,11 @@
}
@Override
+ public String getTag() {
+ return "END_RTIO";
+ }
+
+ @Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
float ratio;
if (stroke.getTotalLength() == 0.0f) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java
new file mode 100644
index 0000000..1338d9d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingLog.java
@@ -0,0 +1,166 @@
+/*
+ * 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.classifier;
+
+import android.app.ActivityThread;
+import android.app.Application;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayDeque;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Keeps track of interesting falsing data.
+ *
+ * By default the log only gets collected on userdebug builds. To turn it on on user:
+ * adb shell setprop debug.falsing_log true
+ *
+ * The log gets dumped as part of the SystemUI services. To dump on demand:
+ * adb shell dumpsys activity service com.android.systemui SystemBars | grep -A 999 FALSING | less
+ *
+ * To dump into logcat:
+ * adb shell setprop debug.falsing_logcat true
+ *
+ * To adjust the log buffer size:
+ * adb shell setprop debug.falsing_log_size 200
+ */
+public class FalsingLog {
+ public static final boolean ENABLED = SystemProperties.getBoolean("debug.falsing_log",
+ Build.IS_DEBUGGABLE);
+ private static final boolean LOGCAT = SystemProperties.getBoolean("debug.falsing_logcat",
+ false);
+
+ public static final boolean VERBOSE = false;
+
+ private static final int MAX_SIZE = SystemProperties.getInt("debug.falsing_log_size", 100);
+
+ private static final String TAG = "FalsingLog";
+
+ private final ArrayDeque<String> mLog = new ArrayDeque<>(MAX_SIZE);
+ private final SimpleDateFormat mFormat = new SimpleDateFormat("MM-dd HH:mm:ss", Locale.US);
+
+ private static FalsingLog sInstance;
+
+ private FalsingLog() {
+ }
+
+ public static void v(String tag, String s) {
+ if (!VERBOSE) {
+ return;
+ }
+ if (LOGCAT) {
+ Log.v(TAG, tag + "\t" + s);
+ }
+ log("V", tag, s);
+ }
+
+ public static void i(String tag, String s) {
+ if (LOGCAT) {
+ Log.i(TAG, tag + "\t" + s);
+ }
+ log("I", tag, s);
+ }
+
+ public static void w(String tag, String s) {
+ if (LOGCAT) {
+ Log.w(TAG, tag + "\t" + s);
+ }
+ log("W", tag, s);
+ }
+
+ public static void e(String tag, String s) {
+ if (LOGCAT) {
+ Log.e(TAG, tag + "\t" + s);
+ }
+ log("E", tag, s);
+ }
+
+ public static synchronized void log(String level, String tag, String s) {
+ if (!ENABLED) {
+ return;
+ }
+ if (sInstance == null) {
+ sInstance = new FalsingLog();
+ }
+
+ if (sInstance.mLog.size() >= MAX_SIZE) {
+ sInstance.mLog.removeFirst();
+ }
+ String entry = new StringBuilder().append(sInstance.mFormat.format(new Date()))
+ .append(" ").append(level).append(" ")
+ .append(tag).append(" ").append(s).toString();
+ sInstance.mLog.add(entry);
+ }
+
+ public static synchronized void dump(PrintWriter pw) {
+ pw.println("FALSING LOG:");
+ if (!ENABLED) {
+ pw.println("Disabled, to enable: setprop debug.falsing_log 1");
+ pw.println();
+ return;
+ }
+ if (sInstance == null || sInstance.mLog.isEmpty()) {
+ pw.println("<empty>");
+ pw.println();
+ return;
+ }
+ for (String s : sInstance.mLog) {
+ pw.println(s);
+ }
+ pw.println();
+ }
+
+ public static synchronized void wtf(String tag, String s) {
+ if (!ENABLED) {
+ return;
+ }
+ e(tag, s);
+
+ Application application = ActivityThread.currentApplication();
+ String fileMessage = "";
+ if (Build.IS_DEBUGGABLE && application != null) {
+ File f = new File(application.getDataDir(), "falsing-"
+ + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + ".txt");
+ PrintWriter pw = null;
+ try {
+ pw = new PrintWriter(f);
+ dump(pw);
+ pw.close();
+ fileMessage = "Log written to " + f.getAbsolutePath();
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write falsing log", e);
+ } finally {
+ if (pw != null) {
+ pw.close();
+ }
+ }
+ } else {
+ Log.e(TAG, "Unable to write log, build must be debuggable.");
+ }
+
+ Log.wtf(TAG, tag + " " + s + "; " + fileMessage);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index c09376b..937f7d3 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -31,6 +31,8 @@
import com.android.systemui.analytics.DataCollector;
import com.android.systemui.statusbar.StatusBarState;
+import java.io.PrintWriter;
+
/**
* When the phone is locked, listens to touch, sensor and phone events and sends them to
* DataCollector and HumanInteractionClassifier.
@@ -102,8 +104,14 @@
}
private boolean shouldSessionBeActive() {
- return isEnabled() && mScreenOn &&
- (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED);
+ if (FalsingLog.ENABLED && FalsingLog.VERBOSE)
+ FalsingLog.v("shouldBeActive", new StringBuilder()
+ .append("enabled=").append(isEnabled() ? 1 : 0)
+ .append(" mScreenOn=").append(mScreenOn ? 1 : 0)
+ .append(" mState=").append(StatusBarState.toShortString(mState))
+ .toString()
+ );
+ return isEnabled() && mScreenOn && (mState == StatusBarState.KEYGUARD);
}
private boolean sessionEntrypoint() {
@@ -122,6 +130,9 @@
}
private void onSessionStart() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onSessionStart", "classifierEnabled=" + isClassiferEnabled());
+ }
mBouncerOn = false;
mSessionActive = true;
@@ -154,6 +165,16 @@
* @return true if the classifier determined that this is not a human interacting with the phone
*/
public boolean isFalseTouch() {
+ if (FalsingLog.ENABLED) {
+ if (!mSessionActive) {
+ FalsingLog.wtf("isFalseTouch", new StringBuilder()
+ .append("Session is not active, yet there's a query for a false touch.")
+ .append(" enabled=").append(isEnabled() ? 1 : 0)
+ .append(" mScreenOn=").append(mScreenOn ? 1 : 0)
+ .append(" mState=").append(StatusBarState.toShortString(mState))
+ .toString());
+ }
+ }
return mHumanInteractionClassifier.isFalseTouch();
}
@@ -173,6 +194,12 @@
}
public void setStatusBarState(int state) {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("setStatusBarState", new StringBuilder()
+ .append("from=").append(StatusBarState.toShortString(mState))
+ .append(" to=").append(StatusBarState.toShortString(state))
+ .toString());
+ }
mState = state;
if (shouldSessionBeActive()) {
sessionEntrypoint();
@@ -182,6 +209,11 @@
}
public void onScreenTurningOn() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onScreenTurningOn", new StringBuilder()
+ .append("from=").append(mScreenOn ? 1 : 0)
+ .toString());
+ }
mScreenOn = true;
if (sessionEntrypoint()) {
mDataCollector.onScreenTurningOn();
@@ -189,6 +221,11 @@
}
public void onScreenOnFromTouch() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onScreenOnFromTouch", new StringBuilder()
+ .append("from=").append(mScreenOn ? 1 : 0)
+ .toString());
+ }
mScreenOn = true;
if (sessionEntrypoint()) {
mDataCollector.onScreenOnFromTouch();
@@ -196,17 +233,30 @@
}
public void onScreenOff() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onScreenOff", new StringBuilder()
+ .append("from=").append(mScreenOn ? 1 : 0)
+ .toString());
+ }
mDataCollector.onScreenOff();
mScreenOn = false;
sessionExitpoint(false /* force */);
}
public void onSucccessfulUnlock() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onSucccessfulUnlock", "");
+ }
mDataCollector.onSucccessfulUnlock();
sessionExitpoint(true /* force */);
}
public void onBouncerShown() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onBouncerShown", new StringBuilder()
+ .append("from=").append(mBouncerOn ? 1 : 0)
+ .toString());
+ }
if (!mBouncerOn) {
mBouncerOn = true;
mDataCollector.onBouncerShown();
@@ -214,6 +264,11 @@
}
public void onBouncerHidden() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onBouncerHidden", new StringBuilder()
+ .append("from=").append(mBouncerOn ? 1 : 0)
+ .toString());
+ }
if (mBouncerOn) {
mBouncerOn = false;
mDataCollector.onBouncerHidden();
@@ -221,6 +276,9 @@
}
public void onQsDown() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onQsDown", "");
+ }
mHumanInteractionClassifier.setType(Classifier.QUICK_SETTINGS);
mDataCollector.onQsDown();
}
@@ -230,6 +288,9 @@
}
public void onTrackingStarted() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onTrackingStarted", "");
+ }
mHumanInteractionClassifier.setType(Classifier.UNLOCK);
mDataCollector.onTrackingStarted();
}
@@ -251,6 +312,9 @@
}
public void onNotificatonStartDraggingDown() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onNotificatonStartDraggingDown", "");
+ }
mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DRAG_DOWN);
mDataCollector.onNotificatonStartDraggingDown();
}
@@ -264,6 +328,9 @@
}
public void onNotificatonStartDismissing() {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onNotificatonStartDismissing", "");
+ }
mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DISMISS);
mDataCollector.onNotificatonStartDismissing();
}
@@ -281,6 +348,9 @@
}
public void onAffordanceSwipingStarted(boolean rightCorner) {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onAffordanceSwipingStarted", "");
+ }
if (rightCorner) {
mHumanInteractionClassifier.setType(Classifier.RIGHT_AFFORDANCE);
} else {
@@ -311,4 +381,14 @@
mHumanInteractionClassifier.onTouchEvent(event);
}
}
+
+ public void dump(PrintWriter pw) {
+ pw.println("FALSING MANAGER");
+ pw.print("classifierEnabled="); pw.println(isClassiferEnabled() ? 1 : 0);
+ pw.print("mSessionActive="); pw.println(mSessionActive ? 1 : 0);
+ pw.print("mBouncerOn="); pw.println(mSessionActive ? 1 : 0);
+ pw.print("mState="); pw.println(StatusBarState.toShortString(mState));
+ pw.print("mScreenOn="); pw.println(mScreenOn ? 1 : 0);
+ pw.println();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 45eb9ad..5e35d76 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -23,6 +23,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.view.MotionEvent;
import java.util.ArrayDeque;
@@ -43,14 +44,12 @@
private final Handler mHandler = new Handler();
private final Context mContext;
- private ArrayList<StrokeClassifier> mStrokeClassifiers = new ArrayList<>();
- private ArrayList<GestureClassifier> mGestureClassifiers = new ArrayList<>();
- private ArrayDeque<MotionEvent> mBufferedEvents = new ArrayDeque<>();
- private final int mStrokeClassifiersSize;
- private final int mGestureClassifiersSize;
+ private final StrokeClassifier[] mStrokeClassifiers;
+ private final GestureClassifier[] mGestureClassifiers;
+ private final ArrayDeque<MotionEvent> mBufferedEvents = new ArrayDeque<>();
+ private final HistoryEvaluator mHistoryEvaluator;
private final float mDpi;
- private HistoryEvaluator mHistoryEvaluator;
private boolean mEnableClassifier = false;
private int mCurrentType = Classifier.GENERIC;
@@ -68,25 +67,27 @@
// If the phone is rotated to landscape, the calculations would be wrong if xdpi and ydpi
// were to be used separately. Due negligible differences in xdpi and ydpi we can just
// take the average.
+ // TODO: make this respect DPI changes.
mDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2.0f;
mClassifierData = new ClassifierData(mDpi);
mHistoryEvaluator = new HistoryEvaluator();
- mStrokeClassifiers.add(new AnglesClassifier(mClassifierData));
- mStrokeClassifiers.add(new SpeedClassifier(mClassifierData));
- mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData));
- mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData));
- mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData));
- mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData));
- mStrokeClassifiers.add(new SpeedAnglesClassifier(mClassifierData));
- mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData));
- mStrokeClassifiers.add(new DirectionClassifier(mClassifierData));
+ mStrokeClassifiers = new StrokeClassifier[]{
+ new AnglesClassifier(mClassifierData),
+ new SpeedClassifier(mClassifierData),
+ new DurationCountClassifier(mClassifierData),
+ new EndPointRatioClassifier(mClassifierData),
+ new EndPointLengthClassifier(mClassifierData),
+ new AccelerationClassifier(mClassifierData),
+ new SpeedAnglesClassifier(mClassifierData),
+ new LengthCountClassifier(mClassifierData),
+ new DirectionClassifier(mClassifierData),
+ };
- mGestureClassifiers.add(new PointerCountClassifier(mClassifierData));
- mGestureClassifiers.add(new ProximityClassifier(mClassifierData));
-
- mStrokeClassifiersSize = mStrokeClassifiers.size();
- mGestureClassifiersSize = mGestureClassifiers.size();
+ mGestureClassifiers = new GestureClassifier[] {
+ new PointerCountClassifier(mClassifierData),
+ new ProximityClassifier(mClassifierData)
+ };
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(HIC_ENABLE), false,
@@ -150,21 +151,30 @@
private void addTouchEvent(MotionEvent event) {
mClassifierData.update(event);
- for (int i = 0; i < mStrokeClassifiersSize; i++) {
- mStrokeClassifiers.get(i).onTouchEvent(event);
+ for (StrokeClassifier c : mStrokeClassifiers) {
+ c.onTouchEvent(event);
}
- for (int i = 0; i < mGestureClassifiersSize; i++) {
- mGestureClassifiers.get(i).onTouchEvent(event);
+ for (GestureClassifier c : mGestureClassifiers) {
+ c.onTouchEvent(event);
}
int size = mClassifierData.getEndingStrokes().size();
for (int i = 0; i < size; i++) {
Stroke stroke = mClassifierData.getEndingStrokes().get(i);
float evaluation = 0.0f;
- for (int j = 0; j < mStrokeClassifiersSize; j++) {
- evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation(
- mCurrentType, stroke);
+ StringBuilder sb = FalsingLog.ENABLED ? new StringBuilder("stroke") : null;
+ for (StrokeClassifier c : mStrokeClassifiers) {
+ float e = c.getFalseTouchEvaluation(mCurrentType, stroke);
+ if (FalsingLog.ENABLED) {
+ String tag = c.getTag();
+ sb.append(" ").append(e >= 1f ? tag : tag.toLowerCase()).append("=").append(e);
+ }
+ evaluation += e;
+ }
+
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i(" addTouchEvent", sb.toString());
}
mHistoryEvaluator.addStroke(evaluation);
}
@@ -172,8 +182,17 @@
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
float evaluation = 0.0f;
- for (int i = 0; i < mGestureClassifiersSize; i++) {
- evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType);
+ StringBuilder sb = FalsingLog.ENABLED ? new StringBuilder("gesture") : null;
+ for (GestureClassifier c : mGestureClassifiers) {
+ float e = c.getFalseTouchEvaluation(mCurrentType);
+ if (FalsingLog.ENABLED) {
+ String tag = c.getTag();
+ sb.append(" ").append(e >= 1f ? tag : tag.toLowerCase()).append("=").append(e);
+ }
+ evaluation += e;
+ }
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i(" addTouchEvent", sb.toString());
}
mHistoryEvaluator.addGesture(evaluation);
setType(Classifier.GENERIC);
@@ -184,18 +203,25 @@
@Override
public void onSensorChanged(SensorEvent event) {
- for (int i = 0; i < mStrokeClassifiers.size(); i++) {
- mStrokeClassifiers.get(i).onSensorChanged(event);
+ for (Classifier c : mStrokeClassifiers) {
+ c.onSensorChanged(event);
}
- for (int i = 0; i < mGestureClassifiers.size(); i++) {
- mGestureClassifiers.get(i).onSensorChanged(event);
+ for (Classifier c : mGestureClassifiers) {
+ c.onSensorChanged(event);
}
}
public boolean isFalseTouch() {
if (mEnableClassifier) {
- return mHistoryEvaluator.getEvaluation() >= 5.0f;
+ float evaluation = mHistoryEvaluator.getEvaluation();
+ boolean result = evaluation >= 5.0f;
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("isFalseTouch", new StringBuilder()
+ .append("eval=").append(evaluation).append(" result=")
+ .append(result ? 1 : 0).toString());
+ }
+ return result;
}
return false;
}
@@ -203,4 +229,9 @@
public boolean isEnabled() {
return mEnableClassifier;
}
+
+ @Override
+ public String getTag() {
+ return "HIC";
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
index cedf467..53678a6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
@@ -28,6 +28,11 @@
}
@Override
+ public String getTag() {
+ return "LEN_CNT";
+ }
+
+ @Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
return LengthCountEvaluator.evaluate(stroke.getTotalLength()
/ Math.max(1.0f, stroke.getCount() - 2));
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
index 5097b63..136c433 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
@@ -29,6 +29,11 @@
}
@Override
+ public String getTag() {
+ return "PTR_CNT";
+ }
+
+ @Override
public void onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 6995064..62adfc8 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -35,6 +35,11 @@
}
@Override
+ public String getTag() {
+ return "PROX";
+ }
+
+ @Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
update(event.values[0] < event.sensor.getMaximumRange(), event.timestamp);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
index d58274d..6df72b1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
@@ -41,6 +41,11 @@
}
@Override
+ public String getTag() {
+ return "SPD_ANG";
+ }
+
+ @Override
public void onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
index 81b78c7..01fcc37 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
@@ -27,6 +27,11 @@
}
@Override
+ public String getTag() {
+ return "SPD";
+ }
+
+ @Override
public float getFalseTouchEvaluation(int type, Stroke stroke) {
float duration = (float) stroke.getDurationNanos() / NANOS_TO_SECONDS;
if (duration == 0.0f) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 6029c23..312d3c5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -684,7 +684,7 @@
doKeyguardLocked(null);
mUpdateMonitor.registerCallback(mUpdateCallback);
}
- mIsPerUserLock = StorageManager.isFileBasedEncryptionEnabled();
+ mIsPerUserLock = StorageManager.isFileEncryptedNativeOrEmulated();
// Most services aren't available until the system reaches the ready state, so we
// send it here when the device first boots.
maybeSendUserPresentBroadcast();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PathInterpolatorBuilder.java b/packages/SystemUI/src/com/android/systemui/qs/PathInterpolatorBuilder.java
new file mode 100644
index 0000000..b8cb92a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/PathInterpolatorBuilder.java
@@ -0,0 +1,153 @@
+/*
+ * 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.qs;
+
+import android.graphics.Path;
+import android.view.animation.BaseInterpolator;
+import android.view.animation.Interpolator;
+
+public class PathInterpolatorBuilder {
+
+ // This governs how accurate the approximation of the Path is.
+ private static final float PRECISION = 0.002f;
+
+ private float[] mX; // x coordinates in the line
+ private float[] mY; // y coordinates in the line
+ private float[] mDist; // Cumulative percentage length of the line
+
+ public PathInterpolatorBuilder(Path path) {
+ initPath(path);
+ }
+
+ public PathInterpolatorBuilder(float controlX, float controlY) {
+ initQuad(controlX, controlY);
+ }
+
+ public PathInterpolatorBuilder(float controlX1, float controlY1, float controlX2,
+ float controlY2) {
+ initCubic(controlX1, controlY1, controlX2, controlY2);
+ }
+
+ private void initQuad(float controlX, float controlY) {
+ Path path = new Path();
+ path.moveTo(0, 0);
+ path.quadTo(controlX, controlY, 1f, 1f);
+ initPath(path);
+ }
+
+ private void initCubic(float x1, float y1, float x2, float y2) {
+ Path path = new Path();
+ path.moveTo(0, 0);
+ path.cubicTo(x1, y1, x2, y2, 1f, 1f);
+ initPath(path);
+ }
+
+ private void initPath(Path path) {
+ float[] pointComponents = path.approximate(PRECISION);
+
+ int numPoints = pointComponents.length / 3;
+ if (pointComponents[1] != 0 || pointComponents[2] != 0
+ || pointComponents[pointComponents.length - 2] != 1
+ || pointComponents[pointComponents.length - 1] != 1) {
+ throw new IllegalArgumentException("The Path must start at (0,0) and end at (1,1)");
+ }
+
+ mX = new float[numPoints];
+ mY = new float[numPoints];
+ mDist = new float[numPoints];
+ float prevX = 0;
+ float prevFraction = 0;
+ int componentIndex = 0;
+ for (int i = 0; i < numPoints; i++) {
+ float fraction = pointComponents[componentIndex++];
+ float x = pointComponents[componentIndex++];
+ float y = pointComponents[componentIndex++];
+ if (fraction == prevFraction && x != prevX) {
+ throw new IllegalArgumentException(
+ "The Path cannot have discontinuity in the X axis.");
+ }
+ if (x < prevX) {
+ throw new IllegalArgumentException("The Path cannot loop back on itself.");
+ }
+ mX[i] = x;
+ mY[i] = y;
+ if (i > 0) {
+ float dx = mX[i] - mX[i - 1];
+ float dy = mY[i] - mY[i - 1];
+ float dist = (float) Math.sqrt(dx * dx + dy * dy);
+ mDist[i] = mDist[i - 1] + dist;
+ }
+ prevX = x;
+ prevFraction = fraction;
+ }
+ // Scale down dist to 0-1.
+ float max = mDist[mDist.length - 1];
+ for (int i = 0; i < numPoints; i++) {
+ mDist[i] /= max;
+ }
+ }
+
+ public Interpolator getXInterpolator() {
+ return new PathInterpolator(mDist, mX);
+ }
+
+ public Interpolator getYInterpolator() {
+ return new PathInterpolator(mDist, mY);
+ }
+
+ private static class PathInterpolator extends BaseInterpolator {
+ private final float[] mX; // x coordinates in the line
+ private final float[] mY; // y coordinates in the line
+
+ private PathInterpolator(float[] xs, float[] ys) {
+ mX = xs;
+ mY = ys;
+ }
+
+ @Override
+ public float getInterpolation(float t) {
+ if (t <= 0) {
+ return 0;
+ } else if (t >= 1) {
+ return 1;
+ }
+ // Do a binary search for the correct x to interpolate between.
+ int startIndex = 0;
+ int endIndex = mX.length - 1;
+
+ while (endIndex - startIndex > 1) {
+ int midIndex = (startIndex + endIndex) / 2;
+ if (t < mX[midIndex]) {
+ endIndex = midIndex;
+ } else {
+ startIndex = midIndex;
+ }
+ }
+
+ float xRange = mX[endIndex] - mX[startIndex];
+ if (xRange == 0) {
+ return mY[startIndex];
+ }
+
+ float tInRange = t - mX[startIndex];
+ float fraction = tInRange / xRange;
+
+ float startY = mY[startIndex];
+ float endY = mY[endIndex];
+ return startY + (fraction * (endY - startY));
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index c8c71cb..b611ba3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -53,7 +53,8 @@
private boolean mOnFirstPage = true;
private TouchAnimator mFirstPageAnimator;
private TouchAnimator mFirstPageDelayedAnimator;
- private TouchAnimator mTranslationAnimator;
+ private TouchAnimator mTranslationXAnimator;
+ private TouchAnimator mTranslationYAnimator;
private TouchAnimator mNonfirstPageAnimator;
private boolean mOnKeyguard;
@@ -138,6 +139,7 @@
firstPageBuilder.setListener(this);
// Fade in the tiles/labels as we reach the final position.
firstPageDelayedBuilder.addFloat(mQsPanel.getTileLayout(), "alpha", 0, 1);
+ clearAnimationState();
mAllViews.clear();
mTopFiveQs.clear();
mAllViews.add((View) mQsPanel.getTileLayout());
@@ -188,10 +190,11 @@
Path path = new Path();
path.moveTo(0, 0);
path.cubicTo(0, 0, 0, 1, 1, 1);
- mTranslationAnimator = new TouchAnimator.Builder()
- .addPath(translationXBuilder.build(), translationYBuilder.build(),
- "position", "position", path)
- .build();
+ PathInterpolatorBuilder interpolatorBuilder = new PathInterpolatorBuilder(0, 0, 0, 1);
+ translationXBuilder.setInterpolator(interpolatorBuilder.getXInterpolator());
+ translationYBuilder.setInterpolator(interpolatorBuilder.getYInterpolator());
+ mTranslationXAnimator = translationXBuilder.build();
+ mTranslationYAnimator = translationYBuilder.build();
}
mNonfirstPageAnimator = new TouchAnimator.Builder()
.addFloat(mQuickQsPanel, "alpha", 1, 0)
@@ -229,7 +232,8 @@
mQuickQsPanel.setAlpha(1);
mFirstPageAnimator.setPosition(position);
mFirstPageDelayedAnimator.setPosition(position);
- mTranslationAnimator.setPosition(position);
+ mTranslationXAnimator.setPosition(position);
+ mTranslationYAnimator.setPosition(position);
} else {
mNonfirstPageAnimator.setPosition(position);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
index db17245..37f2528 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -14,11 +14,8 @@
package com.android.systemui.qs;
-import android.graphics.Path;
-import android.graphics.PathMeasure;
import android.util.FloatProperty;
import android.util.MathUtils;
-import android.util.Pair;
import android.util.Property;
import android.view.View;
import android.view.animation.Interpolator;
@@ -141,19 +138,6 @@
return this;
}
- public Builder addPath(Object target, String xProp, String yProp,
- Path path) {
- return addPath(target, target, xProp, yProp, path);
- }
-
- public Builder addPath(Object xTarget, Object yTarget, String xProp, String yProp,
- Path path) {
- add(new Pair<>(xTarget, yTarget),
- KeyframeSet.ofPath(getProperty(xTarget, xProp, float.class),
- getProperty(yTarget, yProp, float.class), path));
- return this;
- }
-
private void add(Object target, KeyframeSet keyframeSet) {
mTargets.add(target);
mValues.add(keyframeSet);
@@ -241,10 +225,6 @@
public static KeyframeSet ofFloat(Property property, float... values) {
return new FloatKeyframeSet((Property<?, Float>) property, values);
}
-
- public static KeyframeSet ofPath(Property xProp, Property yProp, Path path) {
- return new PathKeyframeSet<>(xProp, yProp, path);
- }
}
private static class FloatKeyframeSet<T> extends KeyframeSet {
@@ -282,31 +262,4 @@
mProperty.set((T) target, (int) (firstFloat + (secondFloat - firstFloat) * amount));
}
}
-
- private static class PathKeyframeSet<T> extends KeyframeSet {
- private final Property<T, Float> mXProp;
- private final Property<T, Float> mYProp;
- private final Path mPath;
- private final PathMeasure mPathMeasure;
- private final float mLength;
- private final float[] mPos;
-
- public PathKeyframeSet(Property<T, Float> xProp, Property<T, Float> yProp, Path path) {
- super(2);
- mXProp = xProp;
- mYProp = yProp;
- mPath = path;
- mPathMeasure = new PathMeasure(mPath, false);
- mLength = mPathMeasure.getLength();
- mPos = new float[2];
- }
-
- @Override
- protected void interpolate(int index, float amount, Object target) {
- Pair<Object, Object> targets = (Pair<Object, Object>) target;
- mPathMeasure.getPosTan(amount * mLength, mPos, null);
- mXProp.set((T) targets.first, mPos[0]);
- mYProp.set((T) targets.second, mPos[1]);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
index cb8f0e7..9a00d95 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -16,6 +16,8 @@
package com.android.systemui.recents;
+import android.graphics.Rect;
+
/**
* Due to the fact that RecentsActivity is per-user, we need to establish an
* interface (this) for the non-system user to register itself for callbacks and to
@@ -27,6 +29,6 @@
void updateRecentsVisibility(boolean visible);
void startScreenPinning();
void sendRecentsDrawnEvent();
- void sendDockingTopTaskEvent(int dragMode);
+ void sendDockingTopTaskEvent(int dragMode, in Rect initialRect);
void sendLaunchRecentsEvent();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index efac0fb3..da77dfd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -43,7 +43,7 @@
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -577,14 +577,15 @@
}
}
- public final void onBusEvent(final DockingTopTaskEvent event) {
+ public final void onBusEvent(final DockedTopTaskEvent event) {
int processUser = sSystemServicesProxy.getProcessUser();
if (!sSystemServicesProxy.isSystemUser(processUser)) {
postToSystemUser(new Runnable() {
@Override
public void run() {
try {
- mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode);
+ mUserToSystemCallbacks.sendDockingTopTaskEvent(event.dragMode,
+ event.initialRect);
} catch (RemoteException e) {
Log.e(TAG, "Callback failed", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index cd1a27f..473956f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -431,13 +431,6 @@
mIgnoreAltTabRelease = false;
mIterateTrigger.stopDozing();
-
- // 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.reset();
}
@Override
@@ -453,6 +446,13 @@
mIsVisible = false;
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
+
+ // 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.reset();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 3ad2cc3..4e11bca 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -47,7 +47,7 @@
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
@@ -66,7 +66,6 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskGrouping;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.tv.views.TaskStackHorizontalGridView;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import com.android.systemui.recents.views.TaskStackView;
import com.android.systemui.recents.views.TaskStackViewScroller;
@@ -569,7 +568,7 @@
// Make sure we inform DividerView before we actually start the activity so we can change
// the resize mode already.
if (ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds)) {
- EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
+ EventBus.getDefault().send(new DockedTopTaskEvent(dragMode, initialBounds));
showRecents(
false /* triggeredFromAltTab */,
dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index f8000b8..ffeb4a1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents;
import android.content.Context;
+import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.EventLog;
@@ -26,7 +27,7 @@
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
@@ -91,8 +92,8 @@
}
@Override
- public void sendDockingTopTaskEvent(int dragMode) throws RemoteException {
- EventBus.getDefault().post(new DockingTopTaskEvent(dragMode));
+ public void sendDockingTopTaskEvent(int dragMode, Rect initialRect) throws RemoteException {
+ EventBus.getDefault().post(new DockedTopTaskEvent(dragMode, initialRect));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
similarity index 74%
rename from packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java
rename to packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
index 264c2c4..f1bc214 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockedTopTaskEvent.java
@@ -16,16 +16,21 @@
package com.android.systemui.recents.events.activity;
+import android.graphics.Rect;
+
import com.android.systemui.recents.events.EventBus;
/**
- * Fires when the user invoked the gesture to dock the top/left task.
+ * Fires when the user invoked the gesture to dock the top/left task after we called into window
+ * manager and before we start recents.
*/
-public class DockingTopTaskEvent extends EventBus.Event {
+public class DockedTopTaskEvent extends EventBus.Event {
public int dragMode;
+ public Rect initialRect;
- public DockingTopTaskEvent(int dragMode) {
+ public DockedTopTaskEvent(int dragMode, Rect initialRect) {
this.dragMode = dragMode;
+ this.initialRect = initialRect;
}
}
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 dd825cb..a91bbd4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -105,6 +105,9 @@
animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
@Override
public void onAnimationStarted() {
+ // If we are launching into another task, cancel the previous task's
+ // window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
if (screenPinningRequested) {
@@ -119,6 +122,9 @@
animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
@Override
public void onAnimationStarted() {
+ // If we are launching into another task, cancel the previous task's
+ // window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
}
};
@@ -146,10 +152,6 @@
animStartedListener);
}
}
-
- // If we are launching into another task, cancel the previous task's
- // window transition
- EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
}
/**
@@ -278,7 +280,8 @@
} else {
layoutAlgorithm.getStackTransformScreenCoordinates(task, stackScroll, mTmpTransform,
null);
- specs.add(composeAnimationSpec(taskView, mTmpTransform, true /* addHeaderBitmap */));
+ specs.add(composeAnimationSpec(stackView, taskView, mTmpTransform,
+ true /* addHeaderBitmap */));
}
return specs;
}
@@ -299,7 +302,8 @@
} else {
layoutAlgorithm.getStackTransformScreenCoordinates(t, stackScroll,
mTmpTransform, null);
- specs.add(composeAnimationSpec(tv, mTmpTransform, true /* addHeaderBitmap */));
+ specs.add(composeAnimationSpec(stackView, tv, mTmpTransform,
+ true /* addHeaderBitmap */));
}
}
}
@@ -318,8 +322,8 @@
/**
* Composes a single animation spec for the given {@link TaskView}
*/
- private static AppTransitionAnimationSpec composeAnimationSpec(TaskView taskView,
- TaskViewTransform transform, boolean addHeaderBitmap) {
+ private static AppTransitionAnimationSpec composeAnimationSpec(TaskStackView stackView,
+ TaskView taskView, TaskViewTransform transform, boolean addHeaderBitmap) {
Bitmap b = null;
if (addHeaderBitmap) {
float scale = transform.scale;
@@ -341,6 +345,10 @@
Rect taskRect = new Rect();
transform.rect.round(taskRect);
+ if (stackView.getStack().getStackFrontMostTask(false /* includeFreeformTasks */) !=
+ taskView.getTask()) {
+ taskRect.bottom = 2 * Recents.getSystemServices().getDisplayRect().height();
+ }
return new AppTransitionAnimationSpec(taskView.getTask().key.id, b, taskRect);
}
}
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 758f4d82..b36d5d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -71,6 +71,8 @@
public static final int ENTER_FROM_HOME_ALPHA_DURATION = 100;
public static final int ENTER_FROM_HOME_TRANSLATION_DURATION = 333;
+ public static final int ENTER_WHILE_DOCKING_DURATION = 150;
+
private static final PathInterpolator ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR =
new PathInterpolator(0, 0, 0, 1f);
private static final PathInterpolator ENTER_FROM_HOME_ALPHA_INTERPOLATOR =
@@ -90,6 +92,9 @@
private static final PathInterpolator FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR =
new PathInterpolator(0.4f, 0, 0.2f, 1f);
+ private static final PathInterpolator ENTER_WHILE_DOCKING_INTERPOLATOR =
+ new PathInterpolator(0, 0, 0.2f, 1f);
+
private TaskStackView mStackView;
private TaskViewTransform mTmpTransform = new TaskViewTransform();
@@ -122,6 +127,8 @@
int offscreenYOffset = stackLayout.mStackRect.height();
int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
R.dimen.recents_task_view_affiliate_group_enter_offset);
+ int launchedWhileDockingOffset = res.getDimensionPixelSize(
+ R.dimen.recents_task_view_launched_while_docking_offset);
// Prepare each of the task views for their enter animation from front to back
List<TaskView> taskViews = mStackView.getTaskViews();
@@ -141,7 +148,7 @@
tv.setVisibility(View.INVISIBLE);
} else if (launchState.launchedHasConfigurationChanged) {
// Just load the views as-is
- } else if (launchState.launchedFromApp) {
+ } else if (launchState.launchedFromApp && !launchState.launchedWhileDocking) {
if (task.isLaunchTarget) {
tv.onPrepareLaunchTargetForEnterAnimation();
} else if (currentTaskOccludesLaunchTarget) {
@@ -159,6 +166,11 @@
bounds.offset(0, offscreenYOffset);
tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right,
(int) bounds.bottom);
+ } else if (launchState.launchedWhileDocking) {
+ RectF bounds = new RectF(mTmpTransform.rect);
+ bounds.offset(0, launchedWhileDockingOffset);
+ tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right,
+ (int) bounds.bottom);
}
}
}
@@ -192,6 +204,7 @@
int taskViewCount = taskViews.size();
for (int i = taskViewCount - 1; i >= 0; i--) {
int taskIndexFromFront = taskViewCount - i - 1;
+ int taskIndexFromBack = i;
final TaskView tv = taskViews.get(i);
Task task = tv.getTask();
boolean currentTaskOccludesLaunchTarget = false;
@@ -205,7 +218,7 @@
stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
null);
- if (launchState.launchedFromApp) {
+ if (launchState.launchedFromApp && !launchState.launchedWhileDocking) {
if (task.isLaunchTarget) {
tv.onStartLaunchTargetEnterAnimation(mTmpTransform,
taskViewEnterFromAppDuration, mStackView.mScreenPinningEnabled,
@@ -241,6 +254,16 @@
.setListener(postAnimationTrigger.decrementOnAnimationEnd());
postAnimationTrigger.increment();
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
+ } else if (launchState.launchedWhileDocking) {
+ // Animate the tasks up
+ AnimationProps taskAnimation = new AnimationProps()
+ .setDuration(AnimationProps.BOUNDS, (int) (ENTER_WHILE_DOCKING_DURATION +
+ (taskIndexFromBack * 2f * FRAME_OFFSET_MS)))
+ .setInterpolator(AnimationProps.BOUNDS,
+ ENTER_WHILE_DOCKING_INTERPOLATOR)
+ .setListener(postAnimationTrigger.decrementOnAnimationEnd());
+ postAnimationTrigger.increment();
+ 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 a5ed32a..6df5884 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -222,9 +222,11 @@
private Range mUnfocusedRange;
private Range mFocusedRange;
- // The initial offset from the top of the stack
+ // The initial offset from the top and bottom of the stack
@ViewDebug.ExportedProperty(category="recents")
private int mInitialTopPeekHeight;
+ @ViewDebug.ExportedProperty(category="recents")
+ private int mInitialBottomPeekHeight;
// The offset from the top when scrolled to the top of the stack
@ViewDebug.ExportedProperty(category="recents")
@@ -322,6 +324,8 @@
res.getFloat(R.integer.recents_layout_unfocused_range_max));
mFocusState = getInitialFocusState();
mInitialTopPeekHeight = res.getDimensionPixelSize(R.dimen.recents_initial_top_peek_size);
+ mInitialBottomPeekHeight =
+ res.getDimensionPixelSize(R.dimen.recents_initial_bottom_peek_size);
mFocusedTopPeekHeight =
res.getDimensionPixelSize(R.dimen.recents_layout_focused_top_peek_size);
mFocusedBottomTaskPeekHeight =
@@ -508,10 +512,13 @@
float initialPeekOffsetNormX = mUnfocusedCurveInterpolator.getX(initialPeekOffsetPct);
float initialFocusedOffset = mStackRect.height() - mInitialTopPeekHeight -
(mHeaderBarHeight * 1f) + 1;
- float initialFocusedOffsetPct = (float) initialFocusedOffset / mStackRect.height();
+ float initialFocusedOffsetPct = initialFocusedOffset / mStackRect.height();
float initialFocusedNormX = mUnfocusedCurveInterpolator.getX(initialFocusedOffsetPct);
- int initialBottomOffset = mStackBottomOffset + mHeaderBarHeight;
- float initialBottomOffsetPct = (float) initialBottomOffset / mStackRect.height();
+ float initialBottomOffset = mStackBottomOffset +
+ (ssp.hasDockedTask()
+ ? mHeaderBarHeight
+ : mInitialBottomPeekHeight);
+ float initialBottomOffsetPct = initialBottomOffset / mStackRect.height();
float initialBottomNormX = mUnfocusedCurveInterpolator.getX(initialBottomOffsetPct);
/*
// If we want to offset the top card slightly
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 2601cd3..e2830a1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -641,9 +641,6 @@
// If we had a deferred animation, cancel that
mDeferredTaskViewLayoutAnimation = null;
- // Cancel all task view animations
- cancelAllTaskViewAnimations();
-
// Synchronize the current set of TaskViews
bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTasksSet,
false /* ignoreTaskOverrides */);
@@ -678,6 +675,10 @@
*/
public void updateTaskViewToTransform(TaskView taskView, TaskViewTransform transform,
AnimationProps animation) {
+ if (taskView.isAnimatingTo(transform)) {
+ return;
+ }
+ taskView.cancelTransformAnimation();
taskView.updateViewPropertiesToTaskTransform(transform, animation,
mRequestUpdateClippingListener);
}
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 0bc7f89..7584a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -147,6 +147,7 @@
AnimateableViewBounds mViewBounds;
private AnimatorSet mTransformAnimation;
+ private final TaskViewTransform mTargetAnimationTransform = new TaskViewTransform();
private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
View mContent;
@@ -319,6 +320,7 @@
// Create the animator
mTransformAnimation = toAnimation.createAnimator(mTmpAnimators);
mTransformAnimation.start();
+ mTargetAnimationTransform.copyFrom(toTransform);
}
}
@@ -338,6 +340,14 @@
}
/**
+ * @return whether we are animating towards {@param transform}
+ */
+ boolean isAnimatingTo(TaskViewTransform transform) {
+ return mTransformAnimation != null && mTransformAnimation.isStarted()
+ && mTargetAnimationTransform.isSame(transform);
+ }
+
+ /**
* Cancels any current transform animations.
*/
public void cancelTransformAnimation() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 0d16a79..dc76e61 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -121,6 +121,18 @@
}
/**
+ * @return whether {@param other} is the same transform as this
+ */
+ public boolean isSame(TaskViewTransform other) {
+ return translationZ == other.translationZ
+ && scale == other.scale
+ && other.alpha == alpha
+ && dimAlpha == other.dimAlpha
+ && visible == other.visible
+ && rect.equals(other.rect);
+ }
+
+ /**
* Resets the current transform.
*/
public void reset() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index a06700d..e64354c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -39,6 +39,7 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.media.MediaActionSound;
import android.net.Uri;
import android.os.AsyncTask;
@@ -407,6 +408,7 @@
private Bitmap mScreenBitmap;
private View mScreenshotLayout;
+ private ScreenshotSelectorView mScreenshotSelectorView;
private ImageView mBackgroundView;
private ImageView mScreenshotView;
private ImageView mScreenshotFlash;
@@ -437,7 +439,11 @@
mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
+ mScreenshotSelectorView = (ScreenshotSelectorView) mScreenshotLayout.findViewById(
+ R.id.global_screenshot_selector);
mScreenshotLayout.setFocusable(true);
+ mScreenshotSelectorView.setFocusable(true);
+ mScreenshotSelectorView.setFocusableInTouchMode(true);
mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
@@ -449,7 +455,7 @@
// Setup the window that we are going to use
mWindowLayoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
- WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
+ WindowManager.LayoutParams.TYPE_SCREENSHOT,
WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
@@ -525,7 +531,8 @@
/**
* Takes a screenshot of the current display and shows an animation.
*/
- void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
+ void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible,
+ int x, int y, int width, int height) {
// We need to orient the screenshot correctly (and the Surface api seems to take screenshots
// only in the natural orientation of the device :!)
mDisplay.getRealMetrics(mDisplayMetrics);
@@ -565,6 +572,13 @@
mScreenBitmap = ss;
}
+ if (width != mDisplayMetrics.widthPixels || height != mDisplayMetrics.heightPixels) {
+ // Crop the screenshot to selected region
+ Bitmap cropped = Bitmap.createBitmap(mScreenBitmap, x, y, width, height);
+ mScreenBitmap.recycle();
+ mScreenBitmap = cropped;
+ }
+
// Optimizations
mScreenBitmap.setHasAlpha(false);
mScreenBitmap.prepareToDraw();
@@ -574,6 +588,71 @@
statusBarVisible, navBarVisible);
}
+ void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
+ mDisplay.getRealMetrics(mDisplayMetrics);
+ takeScreenshot(finisher, statusBarVisible, navBarVisible, 0, 0, mDisplayMetrics.widthPixels,
+ mDisplayMetrics.heightPixels);
+ }
+
+ /**
+ * Displays a screenshot selector
+ */
+ void takeScreenshotPartial(final Runnable finisher, final boolean statusBarVisible,
+ final boolean navBarVisible) {
+ mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+ mScreenshotSelectorView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ ScreenshotSelectorView view = (ScreenshotSelectorView) v;
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ view.startSelection((int) event.getX(), (int) event.getY());
+ return true;
+ case MotionEvent.ACTION_MOVE:
+ view.updateSelection((int) event.getX(), (int) event.getY());
+ return true;
+ case MotionEvent.ACTION_UP:
+ view.setVisibility(View.GONE);
+ mWindowManager.removeView(mScreenshotLayout);
+ final Rect rect = view.getSelectionRect();
+ if (rect != null) {
+ if (rect.width() != 0 && rect.height() != 0) {
+ // Need mScreenshotLayout to handle it after the view disappears
+ mScreenshotLayout.post(new Runnable() {
+ public void run() {
+ takeScreenshot(finisher, statusBarVisible, navBarVisible,
+ rect.left, rect.top, rect.width(), rect.height());
+ }
+ });
+ }
+ }
+
+ view.stopSelection();
+ return true;
+ }
+
+ return false;
+ }
+ });
+ mScreenshotLayout.post(new Runnable() {
+ @Override
+ public void run() {
+ mScreenshotSelectorView.setVisibility(View.VISIBLE);
+ mScreenshotSelectorView.requestFocus();
+ }
+ });
+ }
+
+ /**
+ * Cancels screenshot request
+ */
+ void stopScreenshot() {
+ // If the selector layer still presents on screen, we remove it and resets its state.
+ if (mScreenshotSelectorView.getSelectionRect() != null) {
+ mWindowManager.removeView(mScreenshotLayout);
+ mScreenshotSelectorView.stopSelection();
+ }
+ }
/**
* Starts the animation after taking the screenshot
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSelectorView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSelectorView.java
new file mode 100644
index 0000000..07a9246
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSelectorView.java
@@ -0,0 +1,82 @@
+/*
+ * 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.screenshot;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Draws a selection rectangle while taking screenshot
+ */
+public class ScreenshotSelectorView extends View {
+ private Point mStartPoint;
+ private Rect mSelectionRect;
+ private final Paint mPaintSelection, mPaintBackground;
+
+ public ScreenshotSelectorView(Context context) {
+ this(context, null);
+ }
+
+ public ScreenshotSelectorView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ mPaintBackground = new Paint(Color.BLACK);
+ mPaintBackground.setAlpha(160);
+ mPaintSelection = new Paint(Color.TRANSPARENT);
+ mPaintSelection.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ }
+
+ public void startSelection(int x, int y) {
+ mStartPoint = new Point(x, y);
+ mSelectionRect = new Rect(x, y, x, y);
+ }
+
+ public void updateSelection(int x, int y) {
+ if (mSelectionRect != null) {
+ mSelectionRect.left = Math.min(mStartPoint.x, x);
+ mSelectionRect.right = Math.max(mStartPoint.x, x);
+ mSelectionRect.top = Math.min(mStartPoint.y, y);
+ mSelectionRect.bottom = Math.max(mStartPoint.y, y);
+ invalidate();
+ }
+ }
+
+ public Rect getSelectionRect() {
+ return mSelectionRect;
+ }
+
+ public void stopSelection() {
+ mStartPoint = null;
+ mSelectionRect = null;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawRect(mLeft, mTop, mRight, mBottom, mPaintBackground);
+ if (mSelectionRect != null) {
+ canvas.drawRect(mSelectionRect, mPaintSelection);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 456b5fa..4badc42 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -23,6 +23,7 @@
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+import android.view.WindowManager;
public class TakeScreenshotService extends Service {
private static final String TAG = "TakeScreenshotService";
@@ -32,21 +33,28 @@
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- switch (msg.what) {
- case 1:
- final Messenger callback = msg.replyTo;
- if (mScreenshot == null) {
- mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
+ final Messenger callback = msg.replyTo;
+ Runnable finisher = new Runnable() {
+ @Override
+ public void run() {
+ Message reply = Message.obtain(null, 1);
+ try {
+ callback.send(reply);
+ } catch (RemoteException e) {
}
- mScreenshot.takeScreenshot(new Runnable() {
- @Override public void run() {
- Message reply = Message.obtain(null, 1);
- try {
- callback.send(reply);
- } catch (RemoteException e) {
- }
- }
- }, msg.arg1 > 0, msg.arg2 > 0);
+ }
+ };
+ if (mScreenshot == null) {
+ mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
+ }
+
+ switch (msg.what) {
+ case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
+ mScreenshot.takeScreenshot(finisher, msg.arg1 > 0, msg.arg2 > 0);
+ break;
+ case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
+ mScreenshot.takeScreenshotPartial(finisher, msg.arg1 > 0, msg.arg2 > 0);
+ break;
}
}
};
@@ -55,4 +63,10 @@
public IBinder onBind(Intent intent) {
return new Messenger(mHandler).getBinder();
}
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ if (mScreenshot != null) mScreenshot.stopScreenshot();
+ return true;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index da5cbe7..7cb1f24 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -53,7 +53,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
@@ -123,6 +123,7 @@
private final Rect mDockedInsetRect = new Rect();
private final Rect mOtherInsetRect = new Rect();
private final Rect mLastResizeRect = new Rect();
+ private final Rect mDisplayRect = new Rect();
private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
private DividerWindowManager mWindowManager;
private VelocityTracker mVelocityTracker;
@@ -133,7 +134,8 @@
private boolean mAnimateAfterRecentsDrawn;
private boolean mGrowAfterRecentsDrawn;
private boolean mGrowRecents;
- private Animator mCurrentAnimator;
+ private ValueAnimator mCurrentAnimator;
+ private boolean mEntranceAnimationRunning;
private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
@Override
@@ -411,6 +413,7 @@
mWindowManagerProxy.setResizing(false);
mDockSide = WindowManager.DOCKED_INVALID;
mCurrentAnimator = null;
+ mEntranceAnimationRunning = false;
}
});
mCurrentAnimator = anim;
@@ -594,7 +597,18 @@
}
mLastResizeRect.set(mDockedRect);
- if (taskPosition != TASK_POSITION_SAME) {
+ if (mEntranceAnimationRunning && taskPosition != TASK_POSITION_SAME) {
+ if (mCurrentAnimator != null) {
+ calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
+ } else {
+ calculateBoundsForPosition(isHorizontalDivision() ? mDisplayHeight : mDisplayWidth,
+ mDockSide, mDockedTaskRect);
+ }
+ calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
+ mOtherTaskRect);
+ mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
+ mOtherTaskRect, null);
+ } else if (taskPosition != TASK_POSITION_SAME) {
calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
mOtherRect);
int dockSideInverted = DockedDividerUtils.invertDockSide(mDockSide);
@@ -610,16 +624,17 @@
calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
+ mDisplayRect.set(0, 0, mDisplayWidth, mDisplayHeight);
alignTopLeft(mDockedRect, mDockedTaskRect);
alignTopLeft(mOtherRect, mOtherTaskRect);
mDockedInsetRect.set(mDockedTaskRect);
mOtherInsetRect.set(mOtherTaskRect);
if (dockSideTopLeft(mDockSide)) {
- alignTopLeft(mDockedRect, mDockedInsetRect);
- alignBottomRight(mOtherRect, mOtherInsetRect);
+ alignTopLeft(mDisplayRect, mDockedInsetRect);
+ alignBottomRight(mDisplayRect, mOtherInsetRect);
} else {
- alignBottomRight(mDockedRect, mDockedInsetRect);
- alignTopLeft(mOtherRect, mOtherInsetRect);
+ alignBottomRight(mDisplayRect, mDockedInsetRect);
+ alignTopLeft(mDisplayRect, mOtherInsetRect);
}
applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
taskPositionDocked);
@@ -638,6 +653,9 @@
}
private float getDimFraction(int position, SnapTarget dismissTarget) {
+ if (mEntranceAnimationRunning) {
+ return 0f;
+ }
float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
fraction = Math.max(0, Math.min(fraction, 1f));
fraction = DIM_INTERPOLATOR.getInterpolation(fraction);
@@ -839,12 +857,18 @@
}
}
- public final void onBusEvent(DockingTopTaskEvent dockingEvent) {
- if (dockingEvent.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
+ public final void onBusEvent(DockedTopTaskEvent event) {
+ if (event.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
mGrowAfterRecentsDrawn = false;
mAnimateAfterRecentsDrawn = true;
startDragging(false /* animate */, false /* touching */);
}
+ updateDockSide();
+ int position = DockedDividerUtils.calculatePositionForBounds(event.initialRect,
+ mDockSide, mDividerSize);
+ mEntranceAnimationRunning = true;
+ resizeStack(position, mSnapAlgorithm.getMiddleTarget().position,
+ mSnapAlgorithm.getMiddleTarget());
}
public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
index 7e7fc3a..c0148c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarState.java
@@ -41,4 +41,20 @@
* Status bar is locked and shows the full screen user switcher.
*/
public static final int FULLSCREEN_USER_SWITCHER = 3;
+
+
+ public static String toShortString(int x) {
+ switch (x) {
+ case SHADE:
+ return "SHD";
+ case SHADE_LOCKED:
+ return "SHD_LCK";
+ case KEYGUARD:
+ return "KGRD";
+ case FULLSCREEN_USER_SWITCHER:
+ return "FS_USRSW";
+ default:
+ return "bad_value_" + x;
+ }
+ }
}
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 8a93c5b..bb43899 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -71,7 +71,6 @@
private List<CarNavigationButton> mNavButtons = new ArrayList<CarNavigationButton>();
private int mCurrentFacetIndex;
- private String mCurrentPackageName;
private SparseBooleanArray mFacetHasMultipleAppsCache = new SparseBooleanArray();
public CarNavigationBarController(Context context,
@@ -84,7 +83,6 @@
}
public void taskChanged(String packageName) {
- mCurrentPackageName = packageName;
// If the package name belongs to a filter, then highlight appropriate button in
// the navigation bar.
if (mFacetPackageMap.containsKey(packageName)) {
@@ -298,12 +296,6 @@
return;
}
- // Don't launch the lens picker if it's already running and the
- // user clicks the same facet
- if (packageName.equals(mCurrentPackageName) && index == mCurrentFacetIndex) {
- return;
- }
-
intent.putExtra(EXTRA_FACET_CATEGORIES, mFacetCategories.get(index));
intent.putExtra(EXTRA_FACET_PACKAGES, mFacetPackages.get(index));
// The facet is identified by the index in which it was added to the nav bar.
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 d50e67a..553d7f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -281,7 +281,7 @@
if (lp.width != panelWidth) {
lp.width = panelWidth;
lp.gravity = panelGravity;
- mQsContainer.setLayoutParams(lp);
+ mQsDensityContainer.setLayoutParams(lp);
mQsContainer.post(mUpdateHeader);
}
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 7856f6c..9f97c71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -112,6 +112,7 @@
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
@@ -2263,6 +2264,10 @@
mStatusBarWindowManager.setPanelExpanded(isExpanded);
}
+ public void onScreenTurnedOff() {
+ mFalsingManager.onScreenOff();
+ }
+
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/
@@ -2966,18 +2971,15 @@
KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
}
+ FalsingManager.getInstance(mContext).dump(pw);
+ FalsingLog.dump(pw);
+
pw.println("SharedPreferences:");
for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
}
}
- private String hunStateToString(Entry entry) {
- if (entry == null) return "null";
- if (entry.notification == null) return "corrupt";
- return entry.notification.getPackageName();
- }
-
private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode=");
pw.println(BarTransitions.modeToString(transitions.getMode()));
@@ -4186,7 +4188,6 @@
mDeviceInteractive = false;
mWakeUpComingFromTouch = false;
mWakeUpTouchLocation = null;
- mFalsingManager.onScreenOff();
mStackScroller.setAnimationsEnabled(false);
updateVisibleToUser();
if (mLaunchCameraOnFinishedGoingToSleep) {
@@ -4493,7 +4494,20 @@
}
private void handlePulseWhileDozing(@NonNull PulseCallback callback, int reason) {
- mDozeScrimController.pulse(callback, reason);
+ mDozeScrimController.pulse(new PulseCallback() {
+
+ @Override
+ public void onPulseStarted() {
+ callback.onPulseStarted();
+ mStackScroller.setPulsing(true);
+ }
+
+ @Override
+ public void onPulseFinished() {
+ callback.onPulseFinished();
+ mStackScroller.setPulsing(false);
+ }
+ }, reason);
}
private void handleStopDozing() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 64d8ab2..3eda320 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -89,6 +89,7 @@
private boolean mForceHideScrims;
private boolean mSkipFirstFrame;
private boolean mDontAnimateBouncerChanges;
+ private boolean mKeyguardFadingOutInProgress;
public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim) {
mScrimBehind = scrimBehind;
@@ -342,12 +343,16 @@
if (mOnAnimationFinished != null) {
mOnAnimationFinished.run();
mOnAnimationFinished = null;
+ mKeyguardFadingOutInProgress = false;
}
scrim.setTag(TAG_KEY_ANIM, null);
scrim.setTag(TAG_KEY_ANIM_TARGET, null);
}
});
anim.start();
+ if (mAnimateKeyguardFadingOut) {
+ mKeyguardFadingOutInProgress = true;
+ }
if (mSkipFirstFrame) {
anim.setCurrentPlayTime(16);
}
@@ -382,6 +387,7 @@
&& mOnAnimationFinished != null) {
mOnAnimationFinished.run();
mOnAnimationFinished = null;
+ mKeyguardFadingOutInProgress = false;
}
}
@@ -422,6 +428,10 @@
}
private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) {
+ if (mKeyguardFadingOutInProgress) {
+ return;
+ }
+
ValueAnimator previousAnimator = StackStateAnimator.getChildTag(scrim,
TAG_KEY_ANIM);
float animEndValue = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 0e84f733..2ba1562 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -212,6 +212,7 @@
public void onScreenTurnedOff() {
mScreenTurnedOn = false;
+ mPhoneStatusBar.onScreenTurnedOff();
}
public void notifyDeviceWakeUpRequested() {
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 c6659d1..d9e8bd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -248,9 +248,11 @@
}
@Override
- protected void onFocusLost() {
- super.onFocusLost();
- defocusIfNeeded();
+ protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+ super.onFocusChanged(focused, direction, previouslyFocusedRect);
+ if (!focused) {
+ defocusIfNeeded();
+ }
}
@Override
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 cca3746..2ea9507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -324,6 +324,7 @@
}
};
private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
+ private boolean mPulsing;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -2194,7 +2195,7 @@
}
private void updateNotificationAnimationStates() {
- boolean running = mAnimationsEnabled;
+ boolean running = mAnimationsEnabled || mPulsing;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
@@ -2204,7 +2205,8 @@
}
private void updateAnimationState(View child) {
- updateAnimationState(mAnimationsEnabled && (mIsExpanded || isPinnedHeadsUp(child)), child);
+ updateAnimationState((mAnimationsEnabled || mPulsing)
+ && (mIsExpanded || isPinnedHeadsUp(child)), child);
}
@@ -3322,6 +3324,11 @@
return mIsExpanded;
}
+ public void setPulsing(boolean pulsing) {
+ mPulsing = pulsing;
+ updateNotificationAnimationStates();
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
@@ -3617,7 +3624,6 @@
// ANIMATION_TYPE_DIMMED
new AnimationFilter()
- .animateY()
.animateDimmed(),
// ANIMATION_TYPE_CHANGE_POSITION
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 123165e..ff7ea27 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -34,6 +34,7 @@
import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.util.Log;
import com.android.systemui.Prefs;
@@ -51,7 +52,8 @@
public class PipManager {
private static final String TAG = "PipManager";
private static final boolean DEBUG = false;
- private static final boolean DEBUG_FORCE_ONBOARDING = false;
+ private static final boolean DEBUG_FORCE_ONBOARDING =
+ SystemProperties.getBoolean("debug.tv.pip_force_onboarding", false);
private static PipManager sPipManager;
@@ -66,6 +68,9 @@
public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH = 0x1;
public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH = 0x2;
+
+ private static final int CLOSE_PIP_WHEN_MEDIA_SESSION_GONE_TIMEOUT_MS = 3000;
+
private int mSuspendPipResizingReason;
private static final float SCALE_FACTOR = 1.1f;
@@ -170,6 +175,12 @@
resizePinnedStack(mState);
}
};
+ private final Runnable mClosePipRunnable = new Runnable() {
+ @Override
+ public void run() {
+ closePip();
+ }
+ };
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -281,6 +292,7 @@
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onPipActivityClosed();
}
+ mHandler.removeCallbacks(mClosePipRunnable);
}
/**
@@ -543,6 +555,12 @@
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onMediaControllerChanged();
}
+ if (mPipMediaController == null) {
+ mHandler.postDelayed(mClosePipRunnable,
+ CLOSE_PIP_WHEN_MEDIA_SESSION_GONE_TIMEOUT_MS);
+ } else {
+ mHandler.removeCallbacks(mClosePipRunnable);
+ }
}
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 65654a8..fb50df9 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -1956,6 +1956,43 @@
// Logs that the user has edited the enabled VR listeners.
VR_MANAGE_LISTENERS = 334;
+ // Settings -> Accessibility -> Click after pointer stops moving
+ ACCESSIBILITY_TOGGLE_AUTOCLICK = 335;
+ // Settings -> Sound
+ SOUND = 336;
+ // Settings -> Notifications -> Gear
+ CONFIGURE_NOTIFICATION = 337;
+ // Settings -> Wi-Fi -> Gear
+ CONFIGURE_WIFI = 338;
+ // Settings -> Display -> Display size
+ DISPLAY_SCREEN_ZOOM = 339;
+ // Settings -> Display -> Font size
+ ACCESSIBILITY_FONT_SIZE = 340;
+ // Settings -> Data usage -> Cellular/Wi-Fi data usage
+ DATA_USAGE_LIST = 341;
+ // Settings -> Data usage -> Billing cycle or DATA_USAGE_LIST -> Gear
+ BILLING_CYCLE = 342;
+ // DATA_USAGE_LIST -> Any item or App info -> Data usage
+ APP_DATA_USAGE = 343;
+ // Settings -> Language & input -> Language
+ USER_LOCALE_LIST = 344;
+ // Settings -> Language & input -> Virtual keyboard
+ VIRTUAL_KEYBOARDS = 345;
+ // Settings -> Language & input -> Physical keyboard
+ PHYSICAL_KEYBOARDS = 346;
+ // Settings -> Language & input -> Virtual keyboard -> Add a virtual keyboard
+ ENABLE_VIRTUAL_KEYBOARDS = 347;
+ // Settings -> Data usage -> Data Saver
+ DATA_SAVER_SUMMARY = 348;
+ // Settings -> Data usage -> Data Saver -> Unrestricted data access
+ DATA_USAGE_UNRESTRICTED_ACCESS = 349;
+
+ // Used for generic logging of Settings Preference Persistence, should not be used
+ // outside SharedPreferencesLogger.
+ ACTION_GENERIC_PACKAGE = 350;
+ // Settings -> Apps -> Gear -> Special access
+ SPECIAL_ACCESS = 351;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
index ad70853..284c309 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityGestureDetector.java
@@ -121,9 +121,9 @@
// movement when gesturing, and touch exploring. Based on user testing,
// all gestures started with the initial movement taking less than 100ms.
// When touch exploring, the first movement almost always takes longer than
- // 200ms. From this data, 150ms seems the best value to decide what
+ // 200ms. From this data, 200ms seems the best value to decide what
// kind of interaction it is.
- private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
+ private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 200;
// Time threshold used to determine if a gesture should be cancelled. If
// the finger pauses for longer than this delay, the ongoing gesture is
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 9e6c21c..b4b40ae 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3436,7 +3436,8 @@
case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
- case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: {
+ case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+ case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 4667172..c5a210c 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -150,6 +150,12 @@
int mNumTimeChanged;
/**
+ * The current set of user whitelisted apps for device idle mode, meaning these are allowed
+ * to freely schedule alarms.
+ */
+ int[] mDeviceIdleUserWhitelist = new int[0];
+
+ /**
* For each uid, this is the last time we dispatched an "allow while idle" alarm,
* used to determine the earliest we can dispatch the next such alarm.
*/
@@ -936,6 +942,7 @@
}
publishBinderService(Context.ALARM_SERVICE, mService);
+ publishLocalService(LocalService.class, new LocalService());
}
@Override
@@ -1251,14 +1258,6 @@
flags &= ~AlarmManager.FLAG_IDLE_UNTIL;
}
- // If the caller is a core system component, and not calling to do work on behalf
- // of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED. This means we
- // will allow these alarms to go off as normal even while idle, with no timing
- // restrictions.
- if (callingUid < Process.FIRST_APPLICATION_UID && workSource == null) {
- flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
- }
-
// If this is an exact time alarm, then it can't be batched with other alarms.
if (windowLength == AlarmManager.WINDOW_EXACT) {
flags |= AlarmManager.FLAG_STANDALONE;
@@ -1268,6 +1267,16 @@
// use it to wake early from idle if needed.
if (alarmClock != null) {
flags |= AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE;
+
+ // If the caller is a core system component or on the user's whitelist, and not calling
+ // to do work on behalf of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED.
+ // This means we will allow these alarms to go off as normal even while idle, with no
+ // timing restrictions.
+ } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
+ || Arrays.binarySearch(mDeviceIdleUserWhitelist,
+ UserHandle.getAppId(callingUid)) >= 0)) {
+ flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+ flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
}
setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver,
@@ -1344,6 +1353,12 @@
}
};
+ public final class LocalService {
+ public void setDeviceIdleUserWhitelist(int[] appids) {
+ setDeviceIdleUserWhitelistImpl(appids);
+ }
+ }
+
void dumpImpl(PrintWriter pw) {
synchronized (mLock) {
pw.println("Current Alarm Manager state:");
@@ -1386,6 +1401,7 @@
pw.print(" Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
pw.print(" Num time change events: "); pw.println(mNumTimeChanged);
+ pw.println(" mDeviceIdleUserWhitelist=" + Arrays.toString(mDeviceIdleUserWhitelist));
pw.println();
pw.println(" Next alarm clock information: ");
@@ -1678,6 +1694,12 @@
}
}
+ void setDeviceIdleUserWhitelistImpl(int[] appids) {
+ synchronized (mLock) {
+ mDeviceIdleUserWhitelist = appids;
+ }
+ }
+
AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
synchronized (mLock) {
return mNextAlarmClockForUser.get(userId);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 62fa7d5..7bf4b56 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -120,6 +120,7 @@
private AlarmManager mAlarmManager;
private IBatteryStats mBatteryStats;
private PowerManagerInternal mLocalPowerManager;
+ private AlarmManagerService.LocalService mLocalAlarmManager;
private INetworkPolicyManager mNetworkPolicyManager;
private DisplayManager mDisplayManager;
private SensorManager mSensorManager;
@@ -269,6 +270,17 @@
private int[] mPowerSaveWhitelistAllAppIdArray = new int[0];
/**
+ * App IDs that have been white-listed by the user to opt out of power save restrictions.
+ */
+ private final SparseBooleanArray mPowerSaveWhitelistUserAppIds = new SparseBooleanArray();
+
+ /**
+ * Current app IDs that are in the user power save white list. This array can
+ * be shared with others because it will not be modified once set.
+ */
+ private int[] mPowerSaveWhitelistUserAppIdArray = new int[0];
+
+ /**
* List of end times for UIDs that are temporarily marked as being allowed to access
* the network and acquire wakelocks. Times are in milliseconds.
*/
@@ -964,6 +976,10 @@
return getSystemPowerWhitelistInternal();
}
+ @Override public String[] getUserPowerWhitelist() {
+ return getUserPowerWhitelistInternal();
+ }
+
@Override public String[] getFullPowerWhitelistExceptIdle() {
return getFullPowerWhitelistExceptIdleInternal();
}
@@ -980,6 +996,10 @@
return getAppIdWhitelistInternal();
}
+ @Override public int[] getAppIdUserWhitelist() {
+ return getAppIdUserWhitelistInternal();
+ }
+
@Override public int[] getAppIdTempWhitelist() {
return getAppIdTempWhitelistInternal();
}
@@ -1161,6 +1181,7 @@
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mBatteryStats = BatteryStatsService.getService();
mLocalPowerManager = getLocalService(PowerManagerInternal.class);
+ mLocalAlarmManager = getLocalService(AlarmManagerService.LocalService.class);
mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
mDisplayManager = (DisplayManager) getContext().getSystemService(
@@ -1227,6 +1248,7 @@
getContext().registerReceiver(mReceiver, filter);
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
+ mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
mDisplayManager.registerDisplayListener(mDisplayListener, null);
updateDisplayLocked();
@@ -1291,6 +1313,17 @@
}
}
+ public String[] getUserPowerWhitelistInternal() {
+ synchronized (this) {
+ int size = mPowerSaveWhitelistUserApps.size();
+ String[] apps = new String[size];
+ for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
+ apps[i] = mPowerSaveWhitelistUserApps.keyAt(i);
+ }
+ return apps;
+ }
+ }
+
public String[] getFullPowerWhitelistExceptIdleInternal() {
synchronized (this) {
int size = mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size();
@@ -1351,6 +1384,12 @@
}
}
+ public int[] getAppIdUserWhitelistInternal() {
+ synchronized (this) {
+ return mPowerSaveWhitelistUserAppIdArray;
+ }
+ }
+
public int[] getAppIdTempWhitelistInternal() {
synchronized (this) {
return mTempWhitelistAppIdArray;
@@ -1993,11 +2032,15 @@
private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps,
ArrayMap<String, Integer> userApps, SparseBooleanArray outAppIds) {
outAppIds.clear();
- for (int i=0; i<systemApps.size(); i++) {
- outAppIds.put(systemApps.valueAt(i), true);
+ if (systemApps != null) {
+ for (int i = 0; i < systemApps.size(); i++) {
+ outAppIds.put(systemApps.valueAt(i), true);
+ }
}
- for (int i=0; i<userApps.size(); i++) {
- outAppIds.put(userApps.valueAt(i), true);
+ if (userApps != null) {
+ for (int i = 0; i < userApps.size(); i++) {
+ outAppIds.put(userApps.valueAt(i), true);
+ }
}
int size = outAppIds.size();
int[] appids = new int[size];
@@ -2012,6 +2055,8 @@
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistExceptIdleAppIds);
mPowerSaveWhitelistAllAppIdArray = buildAppIdArray(mPowerSaveWhitelistApps,
mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds);
+ mPowerSaveWhitelistUserAppIdArray = buildAppIdArray(null,
+ mPowerSaveWhitelistUserApps, mPowerSaveWhitelistUserAppIds);
if (mLocalPowerManager != null) {
if (DEBUG) {
Slog.d(TAG, "Setting wakelock whitelist to "
@@ -2019,6 +2064,13 @@
}
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
}
+ if (mLocalAlarmManager != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting alarm whitelist to "
+ + Arrays.toString(mPowerSaveWhitelistUserAppIdArray));
+ }
+ mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
+ }
}
private void updateTempWhitelistAppIdsLocked() {
@@ -2536,6 +2588,15 @@
pw.println();
}
}
+ size = mPowerSaveWhitelistUserAppIds.size();
+ if (size > 0) {
+ pw.println(" Whitelist user app ids:");
+ for (int i = 0; i < size; i++) {
+ pw.print(" ");
+ pw.print(mPowerSaveWhitelistUserAppIds.keyAt(i));
+ pw.println();
+ }
+ }
size = mPowerSaveWhitelistAllAppIds.size();
if (size > 0) {
pw.println(" Whitelist all app ids:");
diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java
index 9313148..8ca675a 100644
--- a/services/core/java/com/android/server/DiskStatsService.java
+++ b/services/core/java/com/android/server/DiskStatsService.java
@@ -80,7 +80,7 @@
reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw);
reportFreeSpace(new File("/system"), "System", pw);
- if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
+ if (StorageManager.isFileEncryptedNativeOnly()) {
pw.println("File-based Encryption: true");
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index a3322fc..4536e04 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -839,11 +839,11 @@
Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
+ ", mDaemonConnected=" + mDaemonConnected);
if (mSystemReady && mDaemonConnected
- && !StorageManager.isNativeFileBasedEncryptionEnabled()) {
+ && !StorageManager.isFileEncryptedNativeOnly()) {
// When booting a device without native support, make sure that our
// user directories are locked or unlocked based on the current
// emulation status.
- final boolean initLocked = StorageManager.isEmulatedFileBasedEncryptionEnabled();
+ final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
for (UserInfo user : users) {
@@ -1940,7 +1940,7 @@
waitForReady();
if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
- if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
+ if (StorageManager.isFileEncryptedNativeOnly()) {
throw new IllegalStateException(
"Emulation not available on device with native FBE");
}
@@ -2811,7 +2811,7 @@
@Override
public boolean isUserKeyUnlocked(int userId) {
- if (StorageManager.isFileBasedEncryptionEnabled()) {
+ if (StorageManager.isFileEncryptedNativeOrEmulated()) {
synchronized (mLock) {
return ArrayUtils.contains(mLocalUnlockedUsers, userId);
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 73d8bdd..30e0ceb 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -446,7 +446,7 @@
// 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()) {
+ if (StorageManager.isFileEncryptedNativeOnly()) {
addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
}
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 3f453dc..306e933 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -27,6 +27,7 @@
import org.xmlpull.v1.XmlPullParserException;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -80,6 +81,8 @@
private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<>();
private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups = new HashMap<>();
private final TextServicesSettings mSettings;
+ @NonNull
+ private final UserManager mUserManager;
public static final class Lifecycle extends SystemService {
private TextServicesManagerService mService;
@@ -109,19 +112,37 @@
mService.systemRunning();
}
}
+
+ @Override
+ public void onUnlockUser(@UserIdInt int userHandle) {
+ // Called on the system server's main looper thread.
+ // TODO: Dispatch this to a worker thread as needed.
+ mService.onUnlockUser(userHandle);
+ }
}
void systemRunning() {
synchronized (mSpellCheckerMap) {
if (!mSystemReady) {
mSystemReady = true;
+ resetInternalState(mSettings.getCurrentUserId());
}
}
}
void onSwitchUser(@UserIdInt int userId) {
synchronized (mSpellCheckerMap) {
- switchUserLocked(userId);
+ resetInternalState(userId);
+ }
+ }
+
+ void onUnlockUser(@UserIdInt int userId) {
+ synchronized(mSpellCheckerMap) {
+ final int currentUserId = mSettings.getCurrentUserId();
+ if (userId != currentUserId) {
+ return;
+ }
+ resetInternalState(currentUserId);
}
}
@@ -129,6 +150,8 @@
mSystemReady = false;
mContext = context;
+ mUserManager = mContext.getSystemService(UserManager.class);
+
final IntentFilter broadcastFilter = new IntentFilter();
broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
@@ -142,14 +165,19 @@
}
mMonitor = new TextServicesMonitor();
mMonitor.register(context, null, true);
- mSettings = new TextServicesSettings(context.getContentResolver(), userId);
+ final boolean useCopyOnWriteSettings =
+ !mSystemReady || !mUserManager.isUserUnlocked(userId);
+ mSettings = new TextServicesSettings(context.getContentResolver(), userId,
+ useCopyOnWriteSettings);
- // "switchUserLocked" initializes the states for the foreground user
- switchUserLocked(userId);
+ // "resetInternalState" initializes the states for the foreground user
+ resetInternalState(userId);
}
- private void switchUserLocked(@UserIdInt int userId) {
- mSettings.setCurrentUserId(userId);
+ private void resetInternalState(@UserIdInt int userId) {
+ final boolean useCopyOnWriteSettings =
+ !mSystemReady || !mUserManager.isUserUnlocked(userId);
+ mSettings.switchCurrentUser(userId, useCopyOnWriteSettings);
updateCurrentProfileIds();
unbindServiceLocked();
buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
@@ -166,8 +194,7 @@
}
void updateCurrentProfileIds() {
- List<UserInfo> profiles =
- UserManager.get(mContext).getProfiles(mSettings.getCurrentUserId());
+ final List<UserInfo> profiles = mUserManager.getProfiles(mSettings.getCurrentUserId());
int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
for (int i = 0; i < currentProfileIds.length; i++) {
currentProfileIds[i] = profiles.get(i).id;
@@ -232,6 +259,9 @@
list.clear();
map.clear();
final PackageManager pm = context.getPackageManager();
+ // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default
+ // behavior of PackageManager is exactly what we want. It by default picks up appropriate
+ // services depending on the unlock state for the specified user.
final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA,
settings.getCurrentUserId());
@@ -774,50 +804,36 @@
synchronized(mSpellCheckerMap) {
pw.println("Current Text Services Manager state:");
- pw.println(" Spell Checker Map:");
- for (Map.Entry<String, SpellCheckerInfo> ent : mSpellCheckerMap.entrySet()) {
- pw.print(" "); pw.print(ent.getKey()); pw.println(":");
- SpellCheckerInfo info = ent.getValue();
- pw.print(" "); pw.print("id="); pw.println(info.getId());
- pw.print(" "); pw.print("comp=");
- pw.println(info.getComponent().toShortString());
- int NS = info.getSubtypeCount();
- for (int i=0; i<NS; i++) {
- SpellCheckerSubtype st = info.getSubtypeAt(i);
- pw.print(" "); pw.print("Subtype #"); pw.print(i); pw.println(":");
- pw.print(" "); pw.print("locale="); pw.println(st.getLocale());
- pw.print(" "); pw.print("extraValue=");
- pw.println(st.getExtraValue());
- }
+ pw.println(" Spell Checkers:");
+ int spellCheckerIndex = 0;
+ for (final SpellCheckerInfo info : mSpellCheckerMap.values()) {
+ pw.println(" Spell Checker #" + spellCheckerIndex);
+ info.dump(pw, " ");
+ ++spellCheckerIndex;
}
pw.println("");
pw.println(" Spell Checker Bind Groups:");
- for (Map.Entry<String, SpellCheckerBindGroup> ent
+ for (final Map.Entry<String, SpellCheckerBindGroup> ent
: mSpellCheckerBindGroups.entrySet()) {
- SpellCheckerBindGroup grp = ent.getValue();
- pw.print(" "); pw.print(ent.getKey()); pw.print(" ");
- pw.print(grp); pw.println(":");
- pw.print(" "); pw.print("mInternalConnection=");
- pw.println(grp.mInternalConnection);
- pw.print(" "); pw.print("mSpellChecker=");
- pw.println(grp.mSpellChecker);
- pw.print(" "); pw.print("mBound="); pw.print(grp.mBound);
- pw.print(" mConnected="); pw.println(grp.mConnected);
- int NL = grp.mListeners.size();
- for (int i=0; i<NL; i++) {
- InternalDeathRecipient listener = grp.mListeners.get(i);
- pw.print(" "); pw.print("Listener #"); pw.print(i); pw.println(":");
- pw.print(" "); pw.print("mTsListener=");
- pw.println(listener.mTsListener);
- pw.print(" "); pw.print("mScListener=");
- pw.println(listener.mScListener);
- pw.print(" "); pw.print("mGroup=");
- pw.println(listener.mGroup);
- pw.print(" "); pw.print("mScLocale=");
- pw.print(listener.mScLocale);
- pw.print(" mUid="); pw.println(listener.mUid);
+ final SpellCheckerBindGroup grp = ent.getValue();
+ pw.println(" " + ent.getKey() + " " + grp + ":");
+ pw.println(" " + "mInternalConnection=" + grp.mInternalConnection);
+ pw.println(" " + "mSpellChecker=" + grp.mSpellChecker);
+ pw.println(" " + "mBound=" + grp.mBound + " mConnected=" + grp.mConnected);
+ final int N = grp.mListeners.size();
+ for (int i = 0; i < N; i++) {
+ final InternalDeathRecipient listener = grp.mListeners.get(i);
+ pw.println(" " + "Listener #" + i + ":");
+ pw.println(" " + "mTsListener=" + listener.mTsListener);
+ pw.println(" " + "mScListener=" + listener.mScListener);
+ pw.println(" " + "mGroup=" + listener.mGroup);
+ pw.println(" " + "mScLocale=" + listener.mScLocale
+ + " mUid=" + listener.mUid);
}
}
+ pw.println("");
+ pw.println(" mSettings:");
+ mSettings.dumpLocked(pw, " ");
}
}
@@ -1037,33 +1053,70 @@
private int[] mCurrentProfileIds = new int[0];
private Object mLock = new Object();
- public TextServicesSettings(ContentResolver resolver, @UserIdInt int userId) {
+ /**
+ * On-memory data store to emulate when {@link #mCopyOnWrite} is {@code true}.
+ */
+ private final HashMap<String, String> mCopyOnWriteDataStore = new HashMap<>();
+ private boolean mCopyOnWrite = false;
+
+ public TextServicesSettings(ContentResolver resolver, @UserIdInt int userId,
+ boolean copyOnWrite) {
mResolver = resolver;
- mCurrentUserId = userId;
+ switchCurrentUser(userId, copyOnWrite);
}
- public void setCurrentUserId(@UserIdInt int userId) {
+ /**
+ * Must be called when the current user is changed.
+ *
+ * @param userId The user ID.
+ * @param copyOnWrite If {@code true}, for each settings key
+ * (e.g. {@link Settings.Secure#SELECTED_SPELL_CHECKER}) we use the actual settings on the
+ * {@link Settings.Secure} until we do the first write operation.
+ */
+ public void switchCurrentUser(@UserIdInt int userId, boolean copyOnWrite) {
if (DBG) {
Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to "
+ userId + ", new ime = " + getSelectedSpellChecker());
}
+ if (mCurrentUserId != userId || mCopyOnWrite != copyOnWrite) {
+ mCopyOnWriteDataStore.clear();
+ // TODO: mCurrentProfileIds should be cleared here.
+ }
// TSMS settings are kept per user, so keep track of current user
mCurrentUserId = userId;
+ mCopyOnWrite = copyOnWrite;
+ // TODO: mCurrentProfileIds should be updated here.
}
private void putString(final String key, final String str) {
- Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
+ if (mCopyOnWrite) {
+ mCopyOnWriteDataStore.put(key, str);
+ } else {
+ Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
+ }
}
private String getString(final String key) {
+ if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
+ final String result = mCopyOnWriteDataStore.get(key);
+ return result != null ? result : "";
+ }
return Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
}
private void putInt(final String key, final int value) {
- Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId);
+ if (mCopyOnWrite) {
+ mCopyOnWriteDataStore.put(key, String.valueOf(value));
+ } else {
+ Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId);
+ }
}
private int getInt(final String key, final int defaultValue) {
+ if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
+ final String result = mCopyOnWriteDataStore.get(key);
+ return result != null ? Integer.valueOf(result) : 0;
+ }
return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId);
}
@@ -1119,6 +1172,12 @@
public boolean isSpellCheckerEnabled() {
return getBoolean(Settings.Secure.SPELL_CHECKER_ENABLED, true);
}
+
+ public void dumpLocked(final PrintWriter pw, final String prefix) {
+ pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
+ pw.println(prefix + "mCurrentProfileIds=" + Arrays.toString(mCurrentProfileIds));
+ pw.println(prefix + "mCopyOnWrite=" + mCopyOnWrite);
+ }
}
// ----------------------------------------------------------------------
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 772a15c..11888ff 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -64,6 +64,7 @@
// Which native processes to dump into dropbox's stack traces
public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
+ "/system/bin/audioserver",
"/system/bin/mediaserver",
"/system/bin/sdcard",
"/system/bin/surfaceflinger"
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f07c1d0..61290e8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -537,9 +537,11 @@
final ActivityStarter mActivityStarter;
/** Task stack change listeners. */
- private RemoteCallbackList<ITaskStackListener> mTaskStackListeners =
+ private final RemoteCallbackList<ITaskStackListener> mTaskStackListeners =
new RemoteCallbackList<ITaskStackListener>();
+ final InstrumentationReporter mInstrumentationReporter = new InstrumentationReporter();
+
public IntentFirewall mIntentFirewall;
// Whether we should show our dialogs (ANR, crash, etc) or just perform their
@@ -5270,6 +5272,10 @@
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer, int userId) {
enforceNotIsolatedCaller("clearApplicationUserData");
+ int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+ userId = mUserController.handleIncomingUser(pid, uid, userId, false,
+ ALLOW_FULL_ONLY, "clearApplicationUserData", null);
final DevicePolicyManagerInternal dpmi = LocalServices
.getService(DevicePolicyManagerInternal.class);
@@ -5277,10 +5283,6 @@
throw new SecurityException("Cannot clear data for a device owner or a profile owner");
}
- int uid = Binder.getCallingUid();
- int pid = Binder.getCallingPid();
- userId = mUserController.handleIncomingUser(pid, uid, userId, false,
- ALLOW_FULL_ONLY, "clearApplicationUserData", null);
long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
@@ -10886,7 +10888,7 @@
* belonging to any running apps.
*/
private void installEncryptionUnawareProviders(int userId) {
- if (!StorageManager.isFileBasedEncryptionEnabled()) {
+ if (!StorageManager.isFileEncryptedNativeOrEmulated()) {
// TODO: eventually pivot this back to look at current user state,
// similar to the comment in UserManager.isUserUnlocked(), but for
// now, if we started apps when "unlocked" then unaware providers
@@ -17796,17 +17798,17 @@
} catch (RemoteException e) {
}
if (ii == null) {
- reportStartInstrumentationFailure(watcher, className,
+ reportStartInstrumentationFailureLocked(watcher, className,
"Unable to find instrumentation info for: " + className);
return false;
}
if (ai == null) {
- reportStartInstrumentationFailure(watcher, className,
+ reportStartInstrumentationFailureLocked(watcher, className,
"Unable to find instrumentation target package: " + ii.targetPackage);
return false;
}
if (!ai.hasCode()) {
- reportStartInstrumentationFailure(watcher, className,
+ reportStartInstrumentationFailureLocked(watcher, className,
"Instrumentation target has no code: " + ii.targetPackage);
return false;
}
@@ -17821,7 +17823,7 @@
+ " not allowed because package " + ii.packageName
+ " does not have a signature matching the target "
+ ii.targetPackage;
- reportStartInstrumentationFailure(watcher, className, msg);
+ reportStartInstrumentationFailureLocked(watcher, className, msg);
throw new SecurityException(msg);
}
@@ -17852,31 +17854,21 @@
* @param cn The component name of the instrumentation.
* @param report The error report.
*/
- private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
+ private void reportStartInstrumentationFailureLocked(IInstrumentationWatcher watcher,
ComponentName cn, String report) {
Slog.w(TAG, report);
- try {
- if (watcher != null) {
- Bundle results = new Bundle();
- results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
- results.putString("Error", report);
- watcher.instrumentationStatus(cn, -1, results);
- }
- } catch (RemoteException e) {
- Slog.w(TAG, e);
+ if (watcher != null) {
+ Bundle results = new Bundle();
+ results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
+ results.putString("Error", report);
+ mInstrumentationReporter.reportStatus(watcher, cn, -1, results);
}
}
void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
if (app.instrumentationWatcher != null) {
- try {
- // NOTE: IInstrumentationWatcher *must* be oneway here
- app.instrumentationWatcher.instrumentationFinished(
- app.instrumentationClass,
- resultCode,
- results);
- } catch (RemoteException e) {
- }
+ mInstrumentationReporter.reportFinished(app.instrumentationWatcher,
+ app.instrumentationClass, resultCode, results);
}
// Can't call out of the system process with a lock held, so post a message.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 39895ac5..d11b436 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -414,6 +414,12 @@
mTaskPositioner.reset();
}
mWindowManager.detachStack(mStackId);
+ if (mStackId == DOCKED_STACK_ID) {
+ // If we removed a docked stack we want to resize it so it resizes all other stacks
+ // in the system to fullscreen.
+ mStackSupervisor.resizeDockedStackLocked(
+ null, null, null, null, null, PRESERVE_WINDOWS);
+ }
}
public void getDisplaySize(Point out) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 28882de..71a1f97 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -32,6 +32,7 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFormatException;
+import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
@@ -39,6 +40,9 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.os.health.HealthStatsParceler;
+import android.os.health.HealthStatsWriter;
+import android.os.health.UidHealthStats;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
import android.telephony.SignalStrength;
@@ -65,7 +69,9 @@
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
import java.util.List;
+import java.util.Map;
/**
* All information we are collecting about things that can happen that impact
@@ -1419,4 +1425,88 @@
}
}
}
+
+ /**
+ * Gets a snapshot of the system health for a particular uid.
+ */
+ @Override
+ public HealthStatsParceler takeUidSnapshot(int requestUid) {
+ if (requestUid != Binder.getCallingUid()) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BATTERY_STATS, null);
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ updateExternalStats("get-health-stats-for-uid",
+ BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
+ synchronized (mStats) {
+ return getHealthStatsForUidLocked(requestUid);
+ }
+ } catch (Exception ex) {
+ Slog.d(TAG, "Crashed while writing for takeUidSnapshot(" + requestUid + ")", ex);
+ throw ex;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Gets a snapshot of the system health for a number of uids.
+ */
+ @Override
+ public HealthStatsParceler[] takeUidSnapshots(int[] requestUids) {
+ if (!onlyCaller(requestUids)) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.BATTERY_STATS, null);
+ }
+ long ident = Binder.clearCallingIdentity();
+ int i=-1;
+ try {
+ updateExternalStats("get-health-stats-for-uids",
+ BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
+ synchronized (mStats) {
+ final int N = requestUids.length;
+ final HealthStatsParceler[] results = new HealthStatsParceler[N];
+ for (i=0; i<N; i++) {
+ results[i] = getHealthStatsForUidLocked(requestUids[i]);
+ }
+ return results;
+ }
+ } catch (Exception ex) {
+ Slog.d(TAG, "Crashed while writing for takeUidSnapshots("
+ + Arrays.toString(requestUids) + ") i=" + i, ex);
+ throw ex;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Returns whether the Binder.getCallingUid is the only thing in requestUids.
+ */
+ private static boolean onlyCaller(int[] requestUids) {
+ final int caller = Binder.getCallingUid();
+ final int N = requestUids.length;
+ for (int i=0; i<N; i++) {
+ if (requestUids[i] != caller) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Gets a HealthStatsParceler for the given uid. You should probably call
+ * updateExternalStats first.
+ */
+ HealthStatsParceler getHealthStatsForUidLocked(int requestUid) {
+ final HealthStatsBatteryStatsWriter writer = new HealthStatsBatteryStatsWriter();
+ final HealthStatsWriter uidWriter = new HealthStatsWriter(UidHealthStats.CONSTANTS);
+ final BatteryStats.Uid uid = mStats.getUidStats().get(requestUid);
+ if (uid != null) {
+ writer.writeUid(uidWriter, mStats, uid);
+ }
+ return new HealthStatsParceler(uidWriter);
+ }
+
}
diff --git a/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
new file mode 100644
index 0000000..39c6ce6
--- /dev/null
+++ b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
@@ -0,0 +1,473 @@
+/*
+ * 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.am;
+
+import android.os.BatteryStats;
+import static android.os.BatteryStats.STATS_SINCE_UNPLUGGED;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.health.HealthKeys;
+import android.os.health.HealthStatsParceler;
+import android.os.health.HealthStatsWriter;
+import android.os.health.PackageHealthStats;
+import android.os.health.ProcessHealthStats;
+import android.os.health.PidHealthStats;
+import android.os.health.ServiceHealthStats;
+import android.os.health.TimerStat;
+import android.os.health.UidHealthStats;
+import android.util.SparseArray;
+
+import java.util.Map;
+
+public class HealthStatsBatteryStatsWriter {
+
+ private final long mNowRealtime;
+ private final long mNowUptime;
+
+ public HealthStatsBatteryStatsWriter() {
+ mNowRealtime = SystemClock.elapsedRealtime();
+ mNowUptime = SystemClock.uptimeMillis();
+ }
+
+ /**
+ * Writes the contents of a BatteryStats.Uid into a HealthStatsWriter.
+ */
+ public void writeUid(HealthStatsWriter uidWriter, BatteryStats bs, BatteryStats.Uid uid) {
+ int N;
+ BatteryStats.Timer timer;
+ SparseArray<? extends BatteryStats.Uid.Sensor> sensors;
+ SparseArray<? extends BatteryStats.Uid.Pid> pids;
+ BatteryStats.ControllerActivityCounter controller;
+ long sum;
+
+ //
+ // It's a little odd for these first four to be here but it's not the end of the
+ // world. It would be easy enough to duplicate them somewhere else if this API
+ // grows.
+ //
+
+ // MEASUREMENT_REALTIME_BATTERY_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS,
+ bs.computeBatteryRealtime(mNowRealtime*1000, STATS_SINCE_UNPLUGGED)/1000);
+
+ // MEASUREMENT_UPTIME_BATTERY_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_UPTIME_BATTERY_MS,
+ bs.computeBatteryUptime(mNowUptime*1000, STATS_SINCE_UNPLUGGED)/1000);
+
+ // MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS,
+ bs.computeBatteryScreenOffRealtime(mNowRealtime*1000, STATS_SINCE_UNPLUGGED)/1000);
+
+ // MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS,
+ bs.computeBatteryScreenOffUptime(mNowUptime*1000, STATS_SINCE_UNPLUGGED)/1000);
+
+ //
+ // Now on to the real per-uid stats...
+ //
+
+ for (final Map.Entry<String,? extends BatteryStats.Uid.Wakelock> entry:
+ uid.getWakelockStats().entrySet()) {
+ final String key = entry.getKey();
+ final BatteryStats.Uid.Wakelock wakelock = entry.getValue();
+
+ // TIMERS_WAKELOCKS_FULL
+ timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_FULL);
+ addTimers(uidWriter, UidHealthStats.TIMERS_WAKELOCKS_FULL, key, timer);
+
+ // TIMERS_WAKELOCKS_PARTIAL
+ timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
+ addTimers(uidWriter, UidHealthStats.TIMERS_WAKELOCKS_PARTIAL, key, timer);
+
+ // TIMERS_WAKELOCKS_WINDOW
+ timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_WINDOW);
+ addTimers(uidWriter, UidHealthStats.TIMERS_WAKELOCKS_WINDOW, key, timer);
+
+ // TIMERS_WAKELOCKS_DRAW
+ timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_DRAW);
+ addTimers(uidWriter, UidHealthStats.TIMERS_WAKELOCKS_DRAW, key, timer);
+ }
+
+ // TIMERS_SYNCS
+ for (final Map.Entry<String,? extends BatteryStats.Timer> entry:
+ uid.getSyncStats().entrySet()) {
+ addTimers(uidWriter, UidHealthStats.TIMERS_SYNCS, entry.getKey(), entry.getValue());
+ }
+
+ // TIMERS_JOBS
+ for (final Map.Entry<String,? extends BatteryStats.Timer> entry:
+ uid.getJobStats().entrySet()) {
+ addTimers(uidWriter, UidHealthStats.TIMERS_JOBS, entry.getKey(), entry.getValue());
+ }
+
+ // TIMERS_SENSORS
+ sensors = uid.getSensorStats();
+ N = sensors.size();
+ for (int i=0; i<N; i++) {
+ int sensorId = sensors.keyAt(i);
+ // Battery Stats stores the GPS sensors with a bogus key in this API. Pull it out
+ // as a separate metric here so as to not expose that in the API.
+ if (sensorId == BatteryStats.Uid.Sensor.GPS) {
+ addTimer(uidWriter, UidHealthStats.TIMER_GPS_SENSOR, sensors.valueAt(i).getSensorTime());
+ } else {
+ addTimers(uidWriter, UidHealthStats.TIMERS_SENSORS, Integer.toString(sensorId),
+ sensors.valueAt(i).getSensorTime());
+ }
+ }
+
+ // STATS_PIDS
+ pids = uid.getPidStats();
+ N = sensors.size();
+ for (int i=0; i<N; i++) {
+ final HealthStatsWriter writer = new HealthStatsWriter(PidHealthStats.CONSTANTS);
+ writePid(writer, pids.valueAt(i));
+ uidWriter.addStats(UidHealthStats.STATS_PIDS, Integer.toString(pids.keyAt(i)), writer);
+ }
+
+ // STATS_PROCESSES
+ for (final Map.Entry<String,? extends BatteryStats.Uid.Proc> entry:
+ uid.getProcessStats().entrySet()) {
+ final HealthStatsWriter writer = new HealthStatsWriter(ProcessHealthStats.CONSTANTS);
+ writeProc(writer, entry.getValue());
+ uidWriter.addStats(UidHealthStats.STATS_PROCESSES, entry.getKey(), writer);
+ }
+
+ // STATS_PACKAGES
+ for (final Map.Entry<String,? extends BatteryStats.Uid.Pkg> entry:
+ uid.getPackageStats().entrySet()) {
+ final HealthStatsWriter writer = new HealthStatsWriter(PackageHealthStats.CONSTANTS);
+ writePkg(writer, entry.getValue());
+ uidWriter.addStats(UidHealthStats.STATS_PACKAGES, entry.getKey(), writer);
+ }
+
+ controller = uid.getWifiControllerActivity();
+ if (controller != null) {
+ // MEASUREMENT_WIFI_IDLE_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS,
+ controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ // MEASUREMENT_WIFI_RX_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS,
+ controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ // MEASUREMENT_WIFI_TX_MS
+ sum = 0;
+ for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
+ sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+ }
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS, sum);
+ // MEASUREMENT_WIFI_POWER_MAMS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS,
+ controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ }
+
+ controller = uid.getBluetoothControllerActivity();
+ if (controller != null) {
+ // MEASUREMENT_BLUETOOTH_IDLE_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS,
+ controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ // MEASUREMENT_BLUETOOTH_RX_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS,
+ controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ // MEASUREMENT_BLUETOOTH_TX_MS
+ sum = 0;
+ for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
+ sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+ }
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS, sum);
+ // MEASUREMENT_BLUETOOTH_POWER_MAMS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS,
+ controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ }
+
+ controller = uid.getModemControllerActivity();
+ if (controller != null) {
+ // MEASUREMENT_MOBILE_IDLE_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS,
+ controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ // MEASUREMENT_MOBILE_RX_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS,
+ controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ // MEASUREMENT_MOBILE_TX_MS
+ sum = 0;
+ for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
+ sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+ }
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS, sum);
+ // MEASUREMENT_MOBILE_POWER_MAMS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS,
+ controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ }
+
+ // MEASUREMENT_WIFI_RUNNING_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS,
+ uid.getWifiRunningTime(mNowRealtime, STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_WIFI_FULL_LOCK_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_FULL_LOCK_MS,
+ uid.getFullWifiLockTime(mNowRealtime, STATS_SINCE_UNPLUGGED));
+
+ // TIMER_WIFI_SCAN
+ uidWriter.addTimer(UidHealthStats.TIMER_WIFI_SCAN,
+ uid.getWifiScanCount(STATS_SINCE_UNPLUGGED),
+ uid.getWifiScanTime(mNowRealtime, STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_WIFI_MULTICAST_MS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_MULTICAST_MS,
+ uid.getWifiMulticastTime(mNowRealtime, STATS_SINCE_UNPLUGGED));
+
+ // TIMER_AUDIO
+ addTimer(uidWriter, UidHealthStats.TIMER_AUDIO, uid.getAudioTurnedOnTimer());
+
+ // TIMER_VIDEO
+ addTimer(uidWriter, UidHealthStats.TIMER_VIDEO, uid.getVideoTurnedOnTimer());
+
+ // TIMER_FLASHLIGHT
+ addTimer(uidWriter, UidHealthStats.TIMER_FLASHLIGHT, uid.getFlashlightTurnedOnTimer());
+
+ // TIMER_CAMERA
+ addTimer(uidWriter, UidHealthStats.TIMER_CAMERA, uid.getCameraTurnedOnTimer());
+
+ // TIMER_FOREGROUND_ACTIVITY
+ addTimer(uidWriter, UidHealthStats.TIMER_FOREGROUND_ACTIVITY, uid.getForegroundActivityTimer());
+
+ // TIMER_BLUETOOTH_SCAN
+ addTimer(uidWriter, UidHealthStats.TIMER_BLUETOOTH_SCAN, uid.getBluetoothScanTimer());
+
+ // TIMER_PROCESS_STATE_TOP_MS
+ addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_TOP_MS,
+ uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_TOP));
+
+ // TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS
+ addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_FOREGROUND_SERVICE_MS,
+ uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE));
+
+ // TIMER_PROCESS_STATE_TOP_SLEEPING_MS
+ addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_TOP_SLEEPING_MS,
+ uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING));
+
+ // TIMER_PROCESS_STATE_FOREGROUND_MS
+ addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_FOREGROUND_MS,
+ uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_FOREGROUND));
+
+ // TIMER_PROCESS_STATE_BACKGROUND_MS
+ addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_BACKGROUND_MS,
+ uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_BACKGROUND));
+
+ // TIMER_PROCESS_STATE_CACHED_MS
+ addTimer(uidWriter, UidHealthStats.TIMER_PROCESS_STATE_CACHED_MS,
+ uid.getProcessStateTimer(BatteryStats.Uid.PROCESS_STATE_CACHED));
+
+ // TIMER_VIBRATOR
+ addTimer(uidWriter, UidHealthStats.TIMER_VIBRATOR, uid.getVibratorOnTimer());
+
+ // MEASUREMENT_OTHER_USER_ACTIVITY_COUNT
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_OTHER_USER_ACTIVITY_COUNT,
+ uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_OTHER,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT,
+ uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_BUTTON,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT,
+ uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_TOUCH,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_MOBILE_RX_BYTES
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_BYTES,
+ uid.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_MOBILE_TX_BYTES
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_BYTES,
+ uid.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_WIFI_RX_BYTES
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_BYTES,
+ uid.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_WIFI_TX_BYTES
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_BYTES,
+ uid.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_BLUETOOTH_RX_BYTES
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_BYTES,
+ uid.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_BLUETOOTH_TX_BYTES
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_BYTES,
+ uid.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_MOBILE_RX_PACKETS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS,
+ uid.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_MOBILE_TX_PACKETS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_PACKETS,
+ uid.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_WIFI_RX_PACKETS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS,
+ uid.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_WIFI_TX_PACKETS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS,
+ uid.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_BLUETOOTH_RX_PACKETS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_PACKETS,
+ uid.getNetworkActivityPackets(BatteryStats.NETWORK_BT_RX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_BLUETOOTH_TX_PACKETS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_PACKETS,
+ uid.getNetworkActivityPackets(BatteryStats.NETWORK_BT_TX_DATA,
+ STATS_SINCE_UNPLUGGED));
+
+ // TIMER_MOBILE_RADIO_ACTIVE
+ uidWriter.addTimer(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE,
+ uid.getMobileRadioActiveCount(STATS_SINCE_UNPLUGGED),
+ uid.getMobileRadioActiveTime(STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_USER_CPU_TIME_US
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_US,
+ uid.getUserCpuTimeUs(STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_SYSTEM_CPU_TIME_US
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_US,
+ uid.getSystemCpuTimeUs(STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_CPU_POWER_MAUS
+ uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_CPU_POWER_MAUS,
+ uid.getCpuPowerMaUs(STATS_SINCE_UNPLUGGED));
+ }
+
+ /**
+ * Writes the contents of a BatteryStats.Uid.Pid into a HealthStatsWriter.
+ */
+ public void writePid(HealthStatsWriter pidWriter, BatteryStats.Uid.Pid pid) {
+ if (pid == null) {
+ return;
+ }
+
+ // MEASUREMENT_WAKE_NESTING_COUNT
+ pidWriter.addMeasurement(PidHealthStats.MEASUREMENT_WAKE_NESTING_COUNT, pid.mWakeNesting);
+
+ // MEASUREMENT_WAKE_SUM_MS
+ pidWriter.addMeasurement(PidHealthStats.MEASUREMENT_WAKE_SUM_MS, pid.mWakeSumMs);
+
+ // MEASUREMENT_WAKE_START_MS
+ pidWriter.addMeasurement(PidHealthStats.MEASUREMENT_WAKE_SUM_MS, pid.mWakeStartMs);
+ }
+
+ /**
+ * Writes the contents of a BatteryStats.Uid.Proc into a HealthStatsWriter.
+ */
+ public void writeProc(HealthStatsWriter procWriter, BatteryStats.Uid.Proc proc) {
+ // MEASUREMENT_USER_TIME_MS
+ procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_USER_TIME_MS,
+ proc.getUserTime(STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_SYSTEM_TIME_MS
+ procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_SYSTEM_TIME_MS,
+ proc.getSystemTime(STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_STARTS_COUNT
+ procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_STARTS_COUNT,
+ proc.getStarts(STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_CRASHES_COUNT
+ procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_CRASHES_COUNT,
+ proc.getNumCrashes(STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_ANR_COUNT
+ procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_ANR_COUNT,
+ proc.getNumAnrs(STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_FOREGROUND_MS
+ procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_FOREGROUND_MS,
+ proc.getForegroundTime(STATS_SINCE_UNPLUGGED));
+ }
+
+ /**
+ * Writes the contents of a BatteryStats.Uid.Pkg into a HealthStatsWriter.
+ */
+ public void writePkg(HealthStatsWriter pkgWriter, BatteryStats.Uid.Pkg pkg) {
+ // STATS_SERVICES
+ for (final Map.Entry<String,? extends BatteryStats.Uid.Pkg.Serv> entry:
+ pkg.getServiceStats().entrySet()) {
+ final HealthStatsWriter writer = new HealthStatsWriter(ServiceHealthStats.CONSTANTS);
+ writeServ(writer, entry.getValue());
+ pkgWriter.addStats(PackageHealthStats.STATS_SERVICES, entry.getKey(), writer);
+ }
+
+ // MEASUREMENTS_WAKEUP_ALARMS_COUNT
+ for (final Map.Entry<String,? extends BatteryStats.Counter> entry:
+ pkg.getWakeupAlarmStats().entrySet()) {
+ final BatteryStats.Counter counter = entry.getValue();
+ if (counter != null) {
+ pkgWriter.addMeasurements(PackageHealthStats.MEASUREMENTS_WAKEUP_ALARMS_COUNT,
+ entry.getKey(), counter.getCountLocked(STATS_SINCE_UNPLUGGED));
+ }
+ }
+ }
+
+ /**
+ * Writes the contents of a BatteryStats.Uid.Pkg.Serv into a HealthStatsWriter.
+ */
+ public void writeServ(HealthStatsWriter servWriter, BatteryStats.Uid.Pkg.Serv serv) {
+ // MEASUREMENT_START_SERVICE_COUNT
+ servWriter.addMeasurement(ServiceHealthStats.MEASUREMENT_START_SERVICE_COUNT,
+ serv.getStarts(STATS_SINCE_UNPLUGGED));
+
+ // MEASUREMENT_LAUNCH_COUNT
+ servWriter.addMeasurement(ServiceHealthStats.MEASUREMENT_LAUNCH_COUNT,
+ serv.getLaunches(STATS_SINCE_UNPLUGGED));
+ }
+
+ /**
+ * Adds a BatteryStats.Timer into a HealthStatsWriter. Safe to pass a null timer.
+ */
+ private void addTimer(HealthStatsWriter writer, int key, BatteryStats.Timer timer) {
+ if (timer != null) {
+ writer.addTimer(key, timer.getCountLocked(STATS_SINCE_UNPLUGGED),
+ timer.getTotalTimeLocked(mNowRealtime, STATS_SINCE_UNPLUGGED));
+ }
+ }
+
+ /**
+ * Adds a named BatteryStats.Timer into a HealthStatsWriter. Safe to pass a null timer.
+ */
+ private void addTimers(HealthStatsWriter writer, int key, String name,
+ BatteryStats.Timer timer) {
+ if (timer != null) {
+ writer.addTimers(key, name, new TimerStat(timer.getCountLocked(STATS_SINCE_UNPLUGGED),
+ timer.getTotalTimeLocked(mNowRealtime, STATS_SINCE_UNPLUGGED)));
+ }
+ }
+}
+
diff --git a/services/core/java/com/android/server/am/InstrumentationReporter.java b/services/core/java/com/android/server/am/InstrumentationReporter.java
new file mode 100644
index 0000000..fdbb73e
--- /dev/null
+++ b/services/core/java/com/android/server/am/InstrumentationReporter.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.server.am;
+
+import android.app.IInstrumentationWatcher;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.ArrayList;
+
+public class InstrumentationReporter {
+ static final boolean DEBUG = false;
+ static final String TAG = ActivityManagerDebugConfig.TAG_AM;
+
+ static final int REPORT_TYPE_STATUS = 0;
+ static final int REPORT_TYPE_FINISHED = 1;
+
+ final Object mLock = new Object();
+ ArrayList<Report> mPendingReports;
+ Thread mThread;
+
+ final class MyThread extends Thread {
+ public MyThread() {
+ super("InstrumentationReporter");
+ if (DEBUG) Slog.d(TAG, "Starting InstrumentationReporter: " + this);
+ }
+
+ @Override
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ boolean waited = false;
+ while (true) {
+ ArrayList<Report> reports;
+ synchronized (mLock) {
+ reports = mPendingReports;
+ mPendingReports = null;
+ if (reports == null || reports.isEmpty()) {
+ if (!waited) {
+ // Sleep for a little bit, to avoid thrashing through threads.
+ try {
+ mLock.wait(10000); // 10 seconds
+ } catch (InterruptedException e) {
+ }
+ waited = true;
+ continue;
+ } else {
+ mThread = null;
+ if (DEBUG) Slog.d(TAG, "Exiting InstrumentationReporter: " + this);
+ return;
+ }
+ }
+ }
+
+ waited = false;
+
+ for (int i=0; i<reports.size(); i++) {
+ final Report rep = reports.get(i);
+ try {
+ if (rep.mType == REPORT_TYPE_STATUS) {
+ if (DEBUG) Slog.d(TAG, "Dispatch status to " + rep.mWatcher
+ + ": " + rep.mName.flattenToShortString()
+ + " code=" + rep.mResultCode + " result=" + rep.mResults);
+ rep.mWatcher.instrumentationStatus(rep.mName, rep.mResultCode,
+ rep.mResults);
+ } else {
+ if (DEBUG) Slog.d(TAG, "Dispatch finished to " + rep.mWatcher
+ + ": " + rep.mName.flattenToShortString()
+ + " code=" + rep.mResultCode + " result=" + rep.mResults);
+ rep.mWatcher.instrumentationFinished(rep.mName, rep.mResultCode,
+ rep.mResults);
+ }
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failure reporting to instrumentation watcher: comp="
+ + rep.mName + " results=" + rep.mResults);
+ }
+ }
+ }
+ }
+ }
+
+ final class Report {
+ final int mType;
+ final IInstrumentationWatcher mWatcher;
+ final ComponentName mName;
+ final int mResultCode;
+ final Bundle mResults;
+
+ Report(int type, IInstrumentationWatcher watcher, ComponentName name, int resultCode,
+ Bundle results) {
+ mType = type;
+ mWatcher = watcher;
+ mName = name;
+ mResultCode = resultCode;
+ mResults = results;
+ }
+ }
+
+ public void reportStatus(IInstrumentationWatcher watcher, ComponentName name, int resultCode,
+ Bundle results) {
+ if (DEBUG) Slog.d(TAG, "Report status to " + watcher
+ + ": " + name.flattenToShortString()
+ + " code=" + resultCode + " result=" + results);
+ report(new Report(REPORT_TYPE_STATUS, watcher, name, resultCode, results));
+ }
+
+ public void reportFinished(IInstrumentationWatcher watcher, ComponentName name, int resultCode,
+ Bundle results) {
+ if (DEBUG) Slog.d(TAG, "Report finished to " + watcher
+ + ": " + name.flattenToShortString()
+ + " code=" + resultCode + " result=" + results);
+ report(new Report(REPORT_TYPE_FINISHED, watcher, name, resultCode, results));
+ }
+
+ private void report(Report report) {
+ synchronized (mLock) {
+ if (mThread == null) {
+ mThread = new MyThread();
+ mThread.start();
+ }
+ if (mPendingReports == null) {
+ mPendingReports = new ArrayList<>();
+ }
+ mPendingReports.add(report);
+ mLock.notifyAll();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 4a5df7a..59c2682 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -584,7 +584,7 @@
}
} else {
Slog.w(TAG, "Mount service not published; guessing locked state based on property");
- return !StorageManager.isFileBasedEncryptionEnabled();
+ return !StorageManager.isFileEncryptedNativeOrEmulated();
}
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index f231f92..3b0b79a 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -718,7 +718,8 @@
public void onUserAdded(int userHandle) {
// If the user is restricted tie them to the parent user's VPN
UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
- if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle
+ && mVpnUsers != null) {
synchronized(Vpn.this) {
try {
addVpnUserLocked(userHandle);
@@ -736,7 +737,8 @@
public void onUserRemoved(int userHandle) {
// clean up if restricted
UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
- if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle
+ && mVpnUsers != null) {
synchronized(Vpn.this) {
try {
removeVpnUserLocked(userHandle);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 95a9875..e1d208e 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -192,6 +192,13 @@
*/
private static final long SYNC_DELAY_ON_CONFLICT = 10*1000; // 10 seconds
+ /**
+ * Generate job ids in the range [MIN_SYNC_JOB_ID, MAX_SYNC_JOB_ID) to avoid conflicts with
+ * other jobs scheduled by the system process.
+ */
+ private static final int MIN_SYNC_JOB_ID = 100000;
+ private static final int MAX_SYNC_JOB_ID = 110000;
+
private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*/";
private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
@@ -249,7 +256,7 @@
synchronized (mScheduledSyncs) {
int newJobId;
do {
- newJobId = mRand.nextInt(Integer.MAX_VALUE);
+ newJobId = MIN_SYNC_JOB_ID + mRand.nextInt(MAX_SYNC_JOB_ID - MIN_SYNC_JOB_ID);
} while (isJobIdInUseLockedH(newJobId));
return newJobId;
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index fba7e7d..d2b77aa 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -47,14 +47,15 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Slog;
import android.util.SparseArray;
-
import android.util.SparseIntArray;
import android.util.TimeUtils;
+
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.ArrayUtils;
import com.android.internal.app.ProcessStats;
@@ -1337,8 +1338,48 @@
Binder.restoreCallingIdentity(identityToken);
}
}
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ResultReceiver resultReceiver) throws RemoteException {
+ (new JobSchedulerShellCommand(JobSchedulerService.this)).exec(
+ this, in, out, err, args, resultReceiver);
+ }
};
+ // Shell command infrastructure: run the given job immediately
+ int executeRunCommand(String pkgName, int userId, int jobId, boolean force) {
+ if (DEBUG) {
+ Slog.v(TAG, "executeRunCommand(): " + pkgName + "/" + userId
+ + " " + jobId + " f=" + force);
+ }
+
+ try {
+ final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0, userId);
+ if (uid < 0) {
+ return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE;
+ }
+
+ synchronized (mLock) {
+ final JobStatus js = mJobs.getJobByUidAndJobId(uid, jobId);
+ if (js == null) {
+ return JobSchedulerShellCommand.CMD_ERR_NO_JOB;
+ }
+
+ js.overrideState = (force) ? JobStatus.OVERRIDE_FULL : JobStatus.OVERRIDE_SOFT;
+ if (!js.isConstraintsSatisfied()) {
+ js.overrideState = 0;
+ return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS;
+ }
+
+ mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
+ }
+ } catch (RemoteException e) {
+ // can't happen
+ }
+ return 0;
+ }
+
private String printContextIdToJobMap(JobStatus[] map, String initial) {
StringBuilder s = new StringBuilder(initial + ": ");
for (int i=0; i<map.length; i++) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
new file mode 100644
index 0000000..2d62c1c
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -0,0 +1,154 @@
+/*
+ * 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.job;
+
+import android.app.AppGlobals;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+
+public class JobSchedulerShellCommand extends ShellCommand {
+ public static final int CMD_ERR_NO_PACKAGE = -1000;
+ public static final int CMD_ERR_NO_JOB = -1001;
+ public static final int CMD_ERR_CONSTRAINTS = -1002;
+
+ JobSchedulerService mInternal;
+ IPackageManager mPM;
+
+ JobSchedulerShellCommand(JobSchedulerService service) {
+ mInternal = service;
+ mPM = AppGlobals.getPackageManager();
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ if ("run".equals(cmd)) {
+ return runJob();
+ } else {
+ return handleDefaultCommands(cmd);
+ }
+ } catch (Exception e) {
+ pw.println("Exception: " + e);
+ }
+ return -1;
+ }
+
+ private int runJob() {
+ try {
+ final int uid = Binder.getCallingUid();
+ final int perm = mPM.checkUidPermission(
+ "android.permission.CHANGE_APP_IDLE_STATE", uid);
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Uid " + uid
+ + " not permitted to force scheduled jobs");
+ }
+ } catch (RemoteException e) {
+ // Can't happen
+ }
+
+ final PrintWriter pw = getOutPrintWriter();
+ boolean force = false;
+ int userId = UserHandle.USER_SYSTEM;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-f":
+ case "--force":
+ force = true;
+ break;
+
+ case "-u":
+ case "--user":
+ userId = Integer.parseInt(getNextArgRequired());
+ break;
+
+ default:
+ pw.println("Error: unknown option '" + opt + "'");
+ return -1;
+ }
+ }
+
+ final String pkgName = getNextArgRequired();
+ final int jobId = Integer.parseInt(getNextArgRequired());
+
+ int ret = mInternal.executeRunCommand(pkgName, userId, jobId, force);
+ switch (ret) {
+ case CMD_ERR_NO_PACKAGE:
+ pw.print("Package not found: ");
+ pw.print(pkgName);
+ pw.print(" / user ");
+ pw.println(userId);
+ break;
+
+ case CMD_ERR_NO_JOB:
+ pw.print("Could not find job ");
+ pw.print(jobId);
+ pw.print(" in package ");
+ pw.print(pkgName);
+ pw.print(" / user ");
+ pw.println(userId);
+ break;
+
+ case CMD_ERR_CONSTRAINTS:
+ pw.print("Job ");
+ pw.print(jobId);
+ pw.print(" in package ");
+ pw.print(pkgName);
+ pw.print(" / user ");
+ pw.print(userId);
+ pw.println(" has functional constraints but --force not specified");
+ break;
+
+ default:
+ // success!
+ pw.print("Running job");
+ if (force) {
+ pw.print(" [FORCED]");
+ }
+ pw.println();
+ break;
+ }
+ return ret;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+
+ pw.println("Job scheduler (jobscheduler) commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println();
+ pw.println(" run [-f | --force] [-u | --user USER_ID] PACKAGE JOB_ID");
+ pw.println(" Trigger immediate execution of a specific scheduled job.");
+ pw.println(" Options:");
+ pw.println(" -f or --force: run the job even if technical constraints such as");
+ pw.println(" connectivity are not currently met");
+ pw.println(" -u or --user: specify which user's job is to be run; the default is");
+ pw.println(" the primary or system user");
+ pw.println();
+ }
+
+}
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 98bf8a9..4a2c88c 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -55,6 +55,11 @@
static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
+ // Soft override: ignore constraints like time that don't affect API availability
+ public static final int OVERRIDE_SOFT = 1;
+ // Full override: ignore all constraints including API-affecting like connectivity
+ public static final int OVERRIDE_FULL = 2;
+
final JobInfo job;
/** Uid of the package requesting this job. */
final int callingUid;
@@ -91,6 +96,9 @@
public int lastEvaluatedPriority;
+ // Used by shell commands
+ public int overrideState = 0;
+
/**
* For use only by ContentObserverController: state it is maintaining about content URIs
* being observed.
@@ -370,7 +378,7 @@
*/
public boolean isReady() {
// Deadline constraint trumps other constraints (except for periodic jobs where deadline
- // (is an implementation detail. A periodic job should only run if it's constraints are
+ // is an implementation detail. A periodic job should only run if its constraints are
// satisfied).
// AppNotIdle implicit constraint trumps all!
return (isConstraintsSatisfied()
@@ -384,12 +392,27 @@
CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
+ // Soft override covers all non-"functional" constraints
+ static final int SOFT_OVERRIDE_CONSTRAINTS =
+ CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY | CONSTRAINT_IDLE;
+
/**
* @return Whether the constraints set on this job are satisfied.
*/
public boolean isConstraintsSatisfied() {
+ if (overrideState == OVERRIDE_FULL) {
+ // force override: the job is always runnable
+ return true;
+ }
+
final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
- final int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
+
+ int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
+ if (overrideState == OVERRIDE_SOFT) {
+ // override: pretend all 'soft' requirements are satisfied
+ sat |= (requiredConstraints & SOFT_OVERRIDE_CONSTRAINTS);
+ }
+
return (sat & req) == req;
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index a626b5b..9cfb590 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -24,6 +24,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -364,9 +365,12 @@
private List<NetworkPolicy> getWifiPolicies() throws RemoteException {
// First gets a list of saved wi-fi networks.
final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
- final Set<String> ssids = new HashSet<>(configs.size());
- for (WifiConfiguration config : configs) {
- ssids.add(removeDoubleQuotes(config.SSID));
+ final int size = configs != null ? configs.size() : 0;
+ final Set<String> ssids = new HashSet<>(size);
+ if (configs != null) {
+ for (WifiConfiguration config : configs) {
+ ssids.add(removeDoubleQuotes(config.SSID));
+ }
}
// Then gets the saved policies.
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index ab3cb83..b13fec1 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -26,7 +26,9 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
+import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.Condition;
@@ -63,15 +65,18 @@
private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
private final SparseArray<CalendarTracker> mTrackers = new SparseArray<>();
private final Handler mWorker;
+ private final HandlerThread mThread;
private boolean mConnected;
private boolean mRegistered;
private boolean mBootComplete; // don't hammer the calendar provider until boot completes.
private long mNextAlarmTime;
- public EventConditionProvider(Looper worker) {
+ public EventConditionProvider() {
if (DEBUG) Slog.d(TAG, "new " + SIMPLE_NAME + "()");
- mWorker = new Handler(worker);
+ mThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
+ mThread.start();
+ mWorker = new Handler(mThread.getLooper());
}
@Override
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 17313b6..6cf3940 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -328,12 +328,16 @@
component.flattenToShortString());
}
- final int[] userIds = mUserProfiles.getCurrentProfileIds();
- for (int userId : userIds) {
- if (enabled) {
- registerServiceLocked(component, userId);
- } else {
- unregisterServiceLocked(component, userId);
+
+ synchronized (mMutex) {
+ final int[] userIds = mUserProfiles.getCurrentProfileIds();
+
+ for (int userId : userIds) {
+ if (enabled) {
+ registerServiceLocked(component, userId);
+ } else {
+ unregisterServiceLocked(component, userId);
+ }
}
}
}
@@ -453,7 +457,7 @@
return queryPackageForServices(packageName, userId, null);
}
- protected Set<ComponentName> queryPackageForServices(String packageName, int userId,
+ public Set<ComponentName> queryPackageForServices(String packageName, int userId,
String category) {
Set<ComponentName> installed = new ArraySet<>();
final PackageManager pm = mContext.getPackageManager();
@@ -636,7 +640,21 @@
}
}
+ /**
+ * Inject a system service into the management list.
+ */
+ public void registerSystemService(final ComponentName name, final int userid) {
+ synchronized (mMutex) {
+ registerServiceLocked(name, userid, true /* isSystem */);
+ }
+ }
+
private void registerServiceLocked(final ComponentName name, final int userid) {
+ registerServiceLocked(name, userid, false /* isSystem */);
+ }
+
+ private void registerServiceLocked(final ComponentName name, final int userid,
+ final boolean isSystem) {
if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
final String servicesBindingTag = name.toString() + "/" + userid;
@@ -694,7 +712,7 @@
try {
mService = asInterface(binder);
info = newServiceInfo(mService, name,
- userid, false /*isSystem*/, this, targetSdkVersion);
+ userid, isSystem, this, targetSdkVersion);
binder.linkToDeath(info, 0);
added = mServices.add(info);
} catch (RemoteException e) {
@@ -890,6 +908,7 @@
return false;
}
if (this.userid == UserHandle.USER_ALL) return true;
+ if (this.userid == UserHandle.USER_SYSTEM) return true;
if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
return supportsProfiles() && mUserProfiles.isCurrentProfile(nid);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 24ffe1f..02c786e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -160,6 +160,7 @@
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
/** {@hide} */
@@ -212,6 +213,7 @@
/** notification_enqueue status value for an ignored notification. */
private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
+ private String mRankerServicePackageName;
private IActivityManager mAm;
AudioManager mAudioManager;
@@ -289,7 +291,7 @@
private final UserProfiles mUserProfiles = new UserProfiles();
private NotificationListeners mListeners;
- private NotificationRanker mRankerServices;
+ private NotificationRankers mRankerServices;
private ConditionProviders mConditionProviders;
private NotificationUsageStats mUsageStats;
@@ -887,6 +889,10 @@
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+ // This is the package that contains the AOSP framework update.
+ mRankerServicePackageName = getContext().getPackageManager()
+ .getServicesSystemSharedLibraryPackageName();
+
mHandler = new WorkerHandler();
mRankingThread.start();
String[] extractorNames;
@@ -931,8 +937,26 @@
importOldBlockDb();
+ // This is a MangedServices object that keeps track of the listeners.
mListeners = new NotificationListeners();
- mRankerServices = new NotificationRanker();
+
+ // This is a MangedServices object that keeps track of the ranker.
+ mRankerServices = new NotificationRankers();
+ // Find the updatable ranker and register it.
+ Set<ComponentName> rankerComponents = mRankerServices.queryPackageForServices(
+ mRankerServicePackageName, UserHandle.USER_SYSTEM, null);
+ Iterator<ComponentName> iterator = rankerComponents.iterator();
+ if (iterator.hasNext()) {
+ ComponentName rankerComponent = iterator.next();
+ if (iterator.hasNext()) {
+ Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
+ } else {
+ mRankerServices.registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
+ }
+ } else {
+ Slog.w(TAG, "could not start ranker service: none found");
+ }
+
mStatusBar = getLocalService(StatusBarManagerInternal.class);
mStatusBar.setNotificationDelegate(mNotificationDelegate);
@@ -1410,13 +1434,9 @@
*/
@Override
public void registerListener(final INotificationListener listener,
- final ComponentName component, final int userid, boolean asRanker) {
+ final ComponentName component, final int userid) {
enforceSystemOrSystemUI("INotificationManager.registerListener");
- if (asRanker) {
- mRankerServices.registerService(listener, component, userid);
- } else {
- mListeners.registerService(listener, component, userid);
- }
+ mListeners.registerService(listener, component, userid);
}
/**
@@ -2138,6 +2158,7 @@
pw.print(listener.component);
}
pw.println(')');
+ pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
pw.println("\n Notification ranker services:");
mRankerServices.dump(pw, filter);
}
@@ -3485,9 +3506,9 @@
}
}
- public class NotificationRanker extends ManagedServices {
+ public class NotificationRankers extends ManagedServices {
- public NotificationRanker() {
+ public NotificationRankers() {
super(getContext(), mHandler, mNotificationList, mUserProfiles);
}
@@ -3530,7 +3551,7 @@
// mServices is the list inside ManagedServices of all the rankers,
// There should be only one, but it's a list, so while we enforce
// singularity elsewhere, we keep it general here, to avoid surprises.
- for (final ManagedServiceInfo info : NotificationRanker.this.mServices) {
+ for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
boolean sbnVisible = isVisibleToListener(sbn, info);
if (!sbnVisible) {
continue;
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 9cdece5..0945065 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -50,7 +50,7 @@
mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
}
if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) {
- mConditionProviders.addSystemProvider(new EventConditionProvider(helper.getLooper()));
+ mConditionProviders.addSystemProvider(new EventConditionProvider());
}
mConditionProviders.setCallback(this);
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 902a3d9..e90fb32 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.content.ComponentName;
@@ -41,6 +42,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IInterface;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -328,16 +330,49 @@
}
@Override
- public void startShortcut(String callingPackage, ShortcutInfo shortcut, Rect sourceBounds,
- Bundle startActivityOptions, UserHandle user) throws RemoteException {
+ public int getShortcutIconResId(String callingPackage, ShortcutInfo shortcut,
+ UserHandle user) {
+ enforceShortcutPermission(user);
+ verifyCallingPackage(callingPackage);
+
+ return mShortcutServiceInternal.getShortcutIconResId(callingPackage, shortcut,
+ user.getIdentifier());
+ }
+
+ @Override
+ public ParcelFileDescriptor getShortcutIconFd(String callingPackage, ShortcutInfo shortcut,
+ UserHandle user) {
+ enforceShortcutPermission(user);
+ verifyCallingPackage(callingPackage);
+
+ return mShortcutServiceInternal.getShortcutIconFd(callingPackage, shortcut,
+ user.getIdentifier());
+ }
+
+ @Override
+ public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
+ Rect sourceBounds, Bundle startActivityOptions, UserHandle user)
+ throws RemoteException {
enforceShortcutPermission(user);
verifyCallingPackage(callingPackage);
final Intent intent = mShortcutServiceInternal.createShortcutIntent(callingPackage,
- shortcut, user.getIdentifier());
- // TODO
- Slog.e(TAG, "startShortcut() not implemented yet, but the intent is " + intent);
- throw new RuntimeException("not implemented yet");
+ packageName, shortcutId, user.getIdentifier());
+ if (intent == null) {
+ return false;
+ }
+ // Note the target activity doesn't have to be exported.
+
+ intent.setSourceBounds(sourceBounds);
+ prepareIntentForLaunch(intent, sourceBounds);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.startActivityAsUser(intent, startActivityOptions, user);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return true;
}
@Override
@@ -369,9 +404,7 @@
Intent launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- launchIntent.setSourceBounds(sourceBounds);
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ prepareIntentForLaunch(launchIntent, sourceBounds);
launchIntent.setPackage(component.getPackageName());
long ident = Binder.clearCallingIdentity();
@@ -408,6 +441,13 @@
}
}
+ private void prepareIntentForLaunch(@NonNull Intent launchIntent,
+ @Nullable Rect sourceBounds) {
+ launchIntent.setSourceBounds(sourceBounds);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
+
@Override
public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds,
Bundle opts, UserHandle user) throws RemoteException {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index b84ffa3..ef53905 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -34,6 +34,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageInstallerSession;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
@@ -58,6 +59,7 @@
import android.system.Os;
import android.system.OsConstants;
import android.system.StructStat;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.ExceptionUtils;
import android.util.MathUtils;
@@ -77,6 +79,7 @@
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -86,6 +89,7 @@
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final String TAG = "PackageInstaller";
private static final boolean LOGD = true;
+ private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
private static final int MSG_COMMIT = 0;
@@ -171,6 +175,25 @@
@GuardedBy("mLock")
private File mInheritedFilesBase;
+ private static final FileFilter sAddedFilter = new FileFilter() {
+ @Override
+ public boolean accept(File file) {
+ // Installers can't stage directories, so it's fine to ignore
+ // entries like "lost+found".
+ if (file.isDirectory()) return false;
+ if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
+ return true;
+ }
+ };
+ private static final FileFilter sRemovedFilter = new FileFilter() {
+ @Override
+ public boolean accept(File file) {
+ if (file.isDirectory()) return false;
+ if (!file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
+ return true;
+ }
+ };
+
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
@@ -346,6 +369,32 @@
}
@Override
+ public void removeSplit(String splitName) {
+ if (TextUtils.isEmpty(params.appPackageName)) {
+ throw new IllegalStateException("Must specify package name to remove a split");
+ }
+ try {
+ createRemoveSplitMarker(splitName);
+ } catch (IOException e) {
+ throw ExceptionUtils.wrap(e);
+ }
+ }
+
+ private void createRemoveSplitMarker(String splitName) throws IOException {
+ try {
+ final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
+ if (!FileUtils.isValidExtFilename(markerName)) {
+ throw new IllegalArgumentException("Invalid marker: " + markerName);
+ }
+ final File target = new File(resolveStageDir(), markerName);
+ target.createNewFile();
+ Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ }
+
+ @Override
public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) {
try {
return openWriteInternal(name, offsetBytes, lengthBytes);
@@ -608,22 +657,28 @@
mResolvedStagedFiles.clear();
mResolvedInheritedFiles.clear();
- final File[] files = mResolvedStageDir.listFiles();
- if (ArrayUtils.isEmpty(files)) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+ final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
+ final List<String> removeSplitList = new ArrayList<>();
+ if (!ArrayUtils.isEmpty(removedFiles)) {
+ for (File removedFile : removedFiles) {
+ final String fileName = removedFile.getName();
+ final String splitName = fileName.substring(
+ 0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
+ removeSplitList.add(splitName);
+ }
}
+ final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
+ if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+ }
// Verify that all staged packages are internally consistent
final ArraySet<String> stagedSplits = new ArraySet<>();
- for (File file : files) {
-
- // Installers can't stage directories, so it's fine to ignore
- // entries like "lost+found".
- if (file.isDirectory()) continue;
-
+ for (File addedFile : addedFiles) {
final ApkLite apk;
try {
- apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
+ apk = PackageParser.parseApkLite(
+ addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
@@ -642,7 +697,7 @@
mSignatures = apk.signatures;
}
- assertApkConsistent(String.valueOf(file), apk);
+ assertApkConsistent(String.valueOf(addedFile), apk);
// Take this opportunity to enforce uniform naming
final String targetName;
@@ -657,8 +712,8 @@
}
final File targetFile = new File(mResolvedStageDir, targetName);
- if (!file.equals(targetFile)) {
- file.renameTo(targetFile);
+ if (!addedFile.equals(targetFile)) {
+ addedFile.renameTo(targetFile);
}
// Base is coming from session
@@ -669,6 +724,27 @@
mResolvedStagedFiles.add(targetFile);
}
+ if (removeSplitList.size() > 0) {
+ // validate split names marked for removal
+ final int flags = mSignatures == null ? PackageManager.GET_SIGNATURES : 0;
+ final PackageInfo pkg = mPm.getPackageInfo(params.appPackageName, flags, userId);
+ for (String splitName : removeSplitList) {
+ if (!ArrayUtils.contains(pkg.splitNames, splitName)) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Split not found: " + splitName);
+ }
+ }
+
+ // ensure we've got appropriate package name, version code and signatures
+ if (mPackageName == null) {
+ mPackageName = pkg.packageName;
+ mVersionCode = pkg.versionCode;
+ }
+ if (mSignatures == null) {
+ mSignatures = pkg.signatures;
+ }
+ }
+
if (params.mode == SessionParams.MODE_FULL_INSTALL) {
// Full installs must include a base package
if (!stagedSplits.contains(null)) {
@@ -707,8 +783,8 @@
for (int i = 0; i < existing.splitNames.length; i++) {
final String splitName = existing.splitNames[i];
final File splitFile = new File(existing.splitCodePaths[i]);
-
- if (!stagedSplits.contains(splitName)) {
+ final boolean splitRemoved = removeSplitList.contains(splitName);
+ if (!stagedSplits.contains(splitName) && !splitRemoved) {
mResolvedInheritedFiles.add(splitFile);
}
}
@@ -748,6 +824,11 @@
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
+ apk.packageName + " inconsistent with " + mPackageName);
}
+ if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
+ + " specified package " + params.appPackageName
+ + " inconsistent with " + apk.packageName);
+ }
if (mVersionCode != apk.versionCode) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
+ " version code " + apk.versionCode + " inconsistent with "
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e180e050..debe072 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2449,7 +2449,7 @@
// since core system apps like SettingsProvider and SystemUI
// can't wait for user to start
final int storageFlags;
- if (StorageManager.isFileBasedEncryptionEnabled()) {
+ if (StorageManager.isFileEncryptedNativeOrEmulated()) {
storageFlags = StorageManager.FLAG_STORAGE_DE;
} else {
storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
@@ -3231,7 +3231,7 @@
* Return if the user key is currently unlocked.
*/
private boolean isUserKeyUnlocked(int userId) {
- if (StorageManager.isFileBasedEncryptionEnabled()) {
+ if (StorageManager.isFileEncryptedNativeOrEmulated()) {
final IMountService mount = IMountService.Stub
.asInterface(ServiceManager.getService("mount"));
if (mount == null) {
@@ -18313,7 +18313,7 @@
* the app.
*/
private boolean maybeMigrateAppData(String volumeUuid, int userId, PackageParser.Package pkg) {
- if (pkg.isSystemApp() && !StorageManager.isFileBasedEncryptionEnabled()
+ if (pkg.isSystemApp() && !StorageManager.isFileEncryptedNativeOrEmulated()
&& PackageManager.APPLY_FORCE_DEVICE_ENCRYPTED) {
final int storageTarget = pkg.applicationInfo.isForceDeviceEncrypted()
? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 28d34a8..d77168c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -95,6 +95,8 @@
return runInstallCommit();
case "install-create":
return runInstallCreate();
+ case "install-remove":
+ return runInstallRemove();
case "install-write":
return runInstallWrite();
case "compile":
@@ -136,11 +138,12 @@
pw.println("Error: must either specify a package size or an APK file");
return 1;
}
- if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
+ if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
- if (doCommitSession(sessionId, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
+ if (doCommitSession(sessionId, false /*logSuccess*/)
+ != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
abandonSession = false;
@@ -225,7 +228,20 @@
final int sessionId = Integer.parseInt(getNextArg());
final String splitName = getNextArg();
final String path = getNextArg();
- return doWriteSession(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
+ return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
+ }
+
+ private int runInstallRemove() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+
+ final int sessionId = Integer.parseInt(getNextArg());
+
+ final String splitName = getNextArg();
+ if (splitName == null) {
+ pw.println("Error: split name not specified");
+ return 1;
+ }
+ return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
}
private int runCompile() throws RemoteException {
@@ -666,12 +682,18 @@
}
}
- String packageName = getNextArg();
+ final String packageName = getNextArg();
if (packageName == null) {
pw.println("Error: package name not specified");
return 1;
}
+ // if a split is specified, just remove it and not the whole package
+ final String splitName = getNextArg();
+ if (splitName != null) {
+ return runRemoveSplit(packageName, splitName);
+ }
+
userId = translateUserId(userId, "runUninstall");
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_SYSTEM;
@@ -709,6 +731,36 @@
}
}
+ private int runRemoveSplit(String packageName, String splitName) throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
+ sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ sessionParams.appPackageName = packageName;
+ final int sessionId =
+ doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
+ boolean abandonSession = true;
+ try {
+ if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/)
+ != PackageInstaller.STATUS_SUCCESS) {
+ return 1;
+ }
+ if (doCommitSession(sessionId, false /*logSuccess*/)
+ != PackageInstaller.STATUS_SUCCESS) {
+ return 1;
+ }
+ abandonSession = false;
+ pw.println("Success");
+ return 0;
+ } finally {
+ if (abandonSession) {
+ try {
+ doAbandonSession(sessionId, false /*logSuccess*/);
+ } catch (Exception ignore) {
+ }
+ }
+ }
+ }
+
private Intent parseIntentAndUser() throws URISyntaxException {
mTargetUser = UserHandle.USER_CURRENT;
Intent intent = Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
@@ -948,7 +1000,7 @@
return sessionId;
}
- private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,
+ private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
boolean logSuccess) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
if ("-".equals(inPath)) {
@@ -1004,6 +1056,27 @@
}
}
+ private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
+ throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ PackageInstaller.Session session = null;
+ try {
+ session = new PackageInstaller.Session(
+ mInterface.getPackageInstaller().openSession(sessionId));
+ session.removeSplit(splitName);
+
+ if (logSuccess) {
+ pw.println("Success");
+ }
+ return 0;
+ } catch (IOException e) {
+ pw.println("Error: failed to remove split; " + e.getMessage());
+ return 1;
+ } finally {
+ IoUtils.closeQuietly(session);
+ }
+ }
+
private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 5382ff1..9d8def6 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -18,7 +18,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.content.ComponentName;
+import android.content.ContentProvider;
import android.content.Context;
import android.content.Intent;
import android.content.pm.IShortcutService;
@@ -30,24 +32,34 @@
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.RectF;
import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.Binder;
-import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
+import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.SELinux;
import android.os.ShellCommand;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.text.format.Formatter;
import android.text.format.Time;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.KeyValueListParser;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -70,6 +82,7 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
@@ -79,29 +92,48 @@
/**
* TODO:
- * - Make save async
*
- * - Add Bitmap support
- *
- * - Implement updateShortcuts
+ * - Detect when already registered instances are passed to APIs again, which might break
+ * internal bitmap handling.
*
* - Listen to PACKAGE_*, remove orphan info, update timestamp for icon res
+ * -> Need to scan all packages when a user starts too.
+ * -> Clear data -> remove all dynamic? but not the pinned?
*
* - Pinned per each launcher package (multiple launchers)
*
- * - Dev option to reset all counts for QA (for now use "adb shell cmd shortcut reset-throttling")
+ * - Make save async (should we?)
*
- * - Load config from settings
+ * - Scan and remove orphan bitmaps (just in case).
+ *
+ * - Backup & restore
*/
public class ShortcutService extends IShortcutService.Stub {
- private static final String TAG = "ShortcutService";
+ static final String TAG = "ShortcutService";
private static final boolean DEBUG = true; // STOPSHIP if true
private static final boolean DEBUG_LOAD = true; // STOPSHIP if true
- private static final int DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
- private static final int DEFAULT_MAX_DAILY_UPDATES = 10;
- private static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 5;
+ @VisibleForTesting
+ static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day
+
+ @VisibleForTesting
+ static final int DEFAULT_MAX_DAILY_UPDATES = 10;
+
+ @VisibleForTesting
+ static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 5;
+
+ @VisibleForTesting
+ static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96;
+
+ @VisibleForTesting
+ static final int DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP = 48;
+
+ @VisibleForTesting
+ static final String DEFAULT_ICON_PERSIST_FORMAT = CompressFormat.PNG.name();
+
+ @VisibleForTesting
+ static final int DEFAULT_ICON_PERSIST_QUALITY = 100;
private static final int SAVE_DELAY_MS = 5000; // in milliseconds.
@@ -114,11 +146,67 @@
@VisibleForTesting
static final String FILENAME_USER_PACKAGES = "shortcuts.xml";
- private static final String DIRECTORY_BITMAPS = "bitmaps";
+ static final String DIRECTORY_BITMAPS = "bitmaps";
private static final String TAG_ROOT = "root";
+ private static final String TAG_PACKAGE = "package";
private static final String TAG_LAST_RESET_TIME = "last_reset_time";
+ private static final String TAG_INTENT_EXTRAS = "intent-extras";
+ private static final String TAG_EXTRAS = "extras";
+ private static final String TAG_SHORTCUT = "shortcut";
+
private static final String ATTR_VALUE = "value";
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_DYNAMIC_COUNT = "dynamic-count";
+ private static final String ATTR_CALL_COUNT = "call-count";
+ private static final String ATTR_LAST_RESET = "last-reset";
+ private static final String ATTR_ID = "id";
+ private static final String ATTR_ACTIVITY = "activity";
+ private static final String ATTR_TITLE = "title";
+ private static final String ATTR_INTENT = "intent";
+ private static final String ATTR_WEIGHT = "weight";
+ private static final String ATTR_TIMESTAMP = "timestamp";
+ private static final String ATTR_FLAGS = "flags";
+ private static final String ATTR_ICON_RES = "icon-res";
+ private static final String ATTR_BITMAP_PATH = "bitmap-path";
+
+ @VisibleForTesting
+ interface ConfigConstants {
+ /**
+ * Key name for the throttling reset interval, in seconds. (long)
+ */
+ String KEY_RESET_INTERVAL_SEC = "reset_interval_sec";
+
+ /**
+ * Key name for the max number of modifying API calls per app for every interval. (int)
+ */
+ String KEY_MAX_DAILY_UPDATES = "max_daily_updates";
+
+ /**
+ * Key name for the max icon dimensions in DP, for non-low-memory devices.
+ */
+ String KEY_MAX_ICON_DIMENSION_DP = "max_icon_dimension_dp";
+
+ /**
+ * Key name for the max icon dimensions in DP, for low-memory devices.
+ */
+ String KEY_MAX_ICON_DIMENSION_DP_LOWRAM = "max_icon_dimension_dp_lowram";
+
+ /**
+ * Key name for the max dynamic shortcuts per app. (int)
+ */
+ String KEY_MAX_SHORTCUTS = "max_shortcuts";
+
+ /**
+ * Key name for icom compression quality, 0-100.
+ */
+ String KEY_ICON_QUALITY = "icon_quality";
+
+ /**
+ * Key name for icon compression format: "PNG", "JPEG" or "WEBP"
+ */
+ String KEY_ICON_FORMAT = "icon_format";
+ }
private final Context mContext;
@@ -136,8 +224,16 @@
* All the information relevant to shortcuts from a single package (per-user).
*
* TODO Move the persisting code to this class.
+ *
+ * Only save/load/dump should look/touch inside this class.
*/
private static class PackageShortcuts {
+ @UserIdInt
+ private final int mUserId;
+
+ @NonNull
+ private final String mPackageName;
+
/**
* All the shortcuts from the package, keyed on IDs.
*/
@@ -151,20 +247,38 @@
/**
* # of times the package has called rate-limited APIs.
*/
- private int mApiCallCountInner;
+ private int mApiCallCount;
/**
- * When {@link #mApiCallCountInner} was reset last time.
+ * When {@link #mApiCallCount} was reset last time.
*/
private long mLastResetTime;
- /**
- * @return the all shortcuts. Note DO NOT add/remove or touch the flags of the result
- * directly, which would cause {@link #mDynamicShortcutCount} to be out of sync.
- */
+ private PackageShortcuts(int userId, String packageName) {
+ mUserId = userId;
+ mPackageName = packageName;
+ }
+
@GuardedBy("mLock")
- public ArrayMap<String, ShortcutInfo> getShortcuts() {
- return mShortcuts;
+ @Nullable
+ public ShortcutInfo findShortcutById(String id) {
+ return mShortcuts.get(id);
+ }
+
+ private ShortcutInfo deleteShortcut(@NonNull ShortcutService s,
+ @NonNull String id) {
+ final ShortcutInfo shortcut = mShortcuts.remove(id);
+ if (shortcut != null) {
+ s.removeIcon(mUserId, shortcut);
+ shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED);
+ }
+ return shortcut;
+ }
+
+ void addShortcut(@NonNull ShortcutService s, @NonNull ShortcutInfo newShortcut) {
+ deleteShortcut(s, newShortcut.getId());
+ s.saveIconAndFixUpShortcut(mUserId, newShortcut);
+ mShortcuts.put(newShortcut.getId(), newShortcut);
}
/**
@@ -195,40 +309,44 @@
// Okay, make it dynamic and add.
newShortcut.addFlags(oldFlags);
- mShortcuts.put(newShortcut.getId(), newShortcut);
+ addShortcut(s, newShortcut);
mDynamicShortcutCount = newDynamicCount;
}
- @GuardedBy("mLock")
- public void deleteAllDynamicShortcuts() {
+ /**
+ * Remove all shortcuts that aren't pinned nor dynamic.
+ */
+ private void removeOrphans(@NonNull ShortcutService s) {
ArrayList<String> removeList = null; // Lazily initialize.
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
- if (!si.isDynamic()) {
- continue;
+ if (si.isPinned() || si.isDynamic()) continue;
+
+ if (removeList == null) {
+ removeList = new ArrayList<>();
}
- if (si.isPinned()) {
- // Still pinned, so don't remove; just make it non-dynamic.
- si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
- } else {
- if (removeList == null) {
- removeList = new ArrayList<>();
- }
- removeList.add(si.getId());
- }
+ removeList.add(si.getId());
}
if (removeList != null) {
for (int i = removeList.size() - 1 ; i >= 0; i--) {
- mShortcuts.remove(removeList.get(i));
+ deleteShortcut(s, removeList.get(i));
}
}
+ }
+
+ @GuardedBy("mLock")
+ public void deleteAllDynamicShortcuts(@NonNull ShortcutService s) {
+ for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+ mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+ }
+ removeOrphans(s);
mDynamicShortcutCount = 0;
}
@GuardedBy("mLock")
- public void deleteDynamicWithId(@NonNull String shortcutId) {
+ public void deleteDynamicWithId(@NonNull ShortcutService s, @NonNull String shortcutId) {
final ShortcutInfo oldShortcut = mShortcuts.get(shortcutId);
if (oldShortcut == null) {
@@ -240,18 +358,30 @@
if (oldShortcut.isPinned()) {
oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
} else {
- mShortcuts.remove(shortcutId);
+ deleteShortcut(s, shortcutId);
}
}
@GuardedBy("mLock")
- public void pinAll(List<String> shortcutIds) {
+ public void replacePinned(@NonNull ShortcutService s, String launcherPackage,
+ List<String> shortcutIds) {
+
+ // TODO Should be per launcherPackage.
+
+ // First, un-pin all shortcuts
+ for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+ mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED);
+ }
+
+ // Then pin ALL
for (int i = shortcutIds.size() - 1; i >= 0; i--) {
final ShortcutInfo shortcut = mShortcuts.get(shortcutIds.get(i));
if (shortcut != null) {
shortcut.addFlags(ShortcutInfo.FLAG_PINNED);
}
}
+
+ removeOrphans(s);
}
/**
@@ -261,16 +391,22 @@
public int getApiCallCount(@NonNull ShortcutService s) {
final long last = s.getLastResetTimeLocked();
+ final long now = s.injectCurrentTimeMillis();
+ if (mLastResetTime > now) {
+ // Clock rewound. // TODO Test it
+ mLastResetTime = now;
+ }
+
// If not reset yet, then reset.
if (mLastResetTime < last) {
- mApiCallCountInner = 0;
+ mApiCallCount = 0;
mLastResetTime = last;
}
- return mApiCallCountInner;
+ return mApiCallCount;
}
/**
- * If the caller app hasn't been throttled yet, increment {@link #mApiCallCountInner}
+ * If the caller app hasn't been throttled yet, increment {@link #mApiCallCount}
* and return true. Otherwise just return false.
*/
@GuardedBy("mLock")
@@ -278,13 +414,13 @@
if (getApiCallCount(s) >= s.mMaxDailyUpdates) {
return false;
}
- mApiCallCountInner++;
+ mApiCallCount++;
return true;
}
@GuardedBy("mLock")
public void resetRateLimitingForCommandLine() {
- mApiCallCountInner = 0;
+ mApiCallCount = 0;
mLastResetTime = 0;
}
@@ -313,21 +449,26 @@
/**
* Max number of dynamic shortcuts that each application can have at a time.
*/
- @GuardedBy("mLock")
private int mMaxDynamicShortcuts;
/**
* Max number of updating API calls that each application can make a day.
*/
- @GuardedBy("mLock")
private int mMaxDailyUpdates;
/**
* Actual throttling-reset interval. By default it's a day.
*/
- @GuardedBy("mLock")
private long mResetInterval;
+ /**
+ * Icon max width/height in pixels.
+ */
+ private int mMaxIconDimension;
+
+ private CompressFormat mIconPersistFormat;
+ private int mIconPersistQuality;
+
public ShortcutService(Context context) {
mContext = Preconditions.checkNotNull(context);
LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
@@ -406,20 +547,79 @@
*/
private void initialize() {
synchronized (mLock) {
- injectLoadConfigurationLocked();
+ loadConfigurationLocked();
loadBaseStateLocked();
}
}
- // Test overrides it to inject different values.
- @VisibleForTesting
- void injectLoadConfigurationLocked() {
- mResetInterval = DEFAULT_RESET_INTERVAL_SEC * 1000L;
- mMaxDailyUpdates = DEFAULT_MAX_DAILY_UPDATES;
- mMaxDynamicShortcuts = DEFAULT_MAX_SHORTCUTS_PER_APP;
+ /**
+ * Load the configuration from Settings.
+ */
+ private void loadConfigurationLocked() {
+ updateConfigurationLocked(injectShortcutManagerConstants());
}
- // === Persistings ===
+ /**
+ * Load the configuration from Settings.
+ */
+ @VisibleForTesting
+ boolean updateConfigurationLocked(String config) {
+ boolean result = true;
+
+ final KeyValueListParser parser = new KeyValueListParser(',');
+ try {
+ parser.setString(config);
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e(TAG, "Bad shortcut manager settings", e);
+ result = false;
+ }
+
+ mResetInterval = parser.getLong(
+ ConfigConstants.KEY_RESET_INTERVAL_SEC, DEFAULT_RESET_INTERVAL_SEC)
+ * 1000L;
+
+ mMaxDailyUpdates = (int) parser.getLong(
+ ConfigConstants.KEY_MAX_DAILY_UPDATES, DEFAULT_MAX_DAILY_UPDATES);
+
+ mMaxDynamicShortcuts = (int) parser.getLong(
+ ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_APP);
+
+ final int iconDimensionDp = injectIsLowRamDevice()
+ ? (int) parser.getLong(
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM,
+ DEFAULT_MAX_ICON_DIMENSION_LOWRAM_DP)
+ : (int) parser.getLong(
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP,
+ DEFAULT_MAX_ICON_DIMENSION_DP);
+
+ mMaxIconDimension = injectDipToPixel(iconDimensionDp);
+
+ mIconPersistFormat = CompressFormat.valueOf(
+ parser.getString(ConfigConstants.KEY_ICON_FORMAT, DEFAULT_ICON_PERSIST_FORMAT));
+
+ mIconPersistQuality = (int) parser.getLong(
+ ConfigConstants.KEY_ICON_QUALITY,
+ DEFAULT_ICON_PERSIST_QUALITY);
+
+ return result;
+ }
+
+ @VisibleForTesting
+ String injectShortcutManagerConstants() {
+ return android.provider.Settings.Global.getString(
+ mContext.getContentResolver(),
+ android.provider.Settings.Global.SHORTCUT_MANAGER_CONSTANTS);
+ }
+
+ @VisibleForTesting
+ int injectDipToPixel(int dip) {
+ return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
+ mContext.getResources().getDisplayMetrics());
+ }
+
+ // === Persisting ===
@Nullable
private String parseStringAttribute(XmlPullParser parser, String attribute) {
@@ -605,23 +805,24 @@
// Body.
for (int i = 0; i < packages.size(); i++) {
final String packageName = packages.keyAt(i);
- final PackageShortcuts shortcuts = packages.valueAt(i);
+ final PackageShortcuts packageShortcuts = packages.valueAt(i);
// TODO Move this to PackageShortcuts.
- out.startTag(null, "package");
+ out.startTag(null, TAG_PACKAGE);
- writeAttr(out, "name", packageName);
- writeAttr(out, "dynamic-count", shortcuts.mDynamicShortcutCount);
- writeAttr(out, "call-count", shortcuts.mApiCallCountInner);
- writeAttr(out, "last-reset", shortcuts.mLastResetTime);
+ writeAttr(out, ATTR_NAME, packageName);
+ writeAttr(out, ATTR_DYNAMIC_COUNT, packageShortcuts.mDynamicShortcutCount);
+ writeAttr(out, ATTR_CALL_COUNT, packageShortcuts.mApiCallCount);
+ writeAttr(out, ATTR_LAST_RESET, packageShortcuts.mLastResetTime);
- final int size = shortcuts.getShortcuts().size();
+ final ArrayMap<String, ShortcutInfo> shortcuts = packageShortcuts.mShortcuts;
+ final int size = shortcuts.size();
for (int j = 0; j < size; j++) {
- saveShortcut(out, shortcuts.getShortcuts().valueAt(j));
+ saveShortcut(out, shortcuts.valueAt(j));
}
- out.endTag(null, "package");
+ out.endTag(null, TAG_PACKAGE);
}
// Epilogue.
@@ -638,23 +839,23 @@
private void saveShortcut(XmlSerializer out, ShortcutInfo si)
throws IOException, XmlPullParserException {
- out.startTag(null, "shortcut");
- writeAttr(out, "id", si.getId());
+ out.startTag(null, TAG_SHORTCUT);
+ writeAttr(out, ATTR_ID, si.getId());
// writeAttr(out, "package", si.getPackageName()); // not needed
- writeAttr(out, "activity", si.getActivityComponent());
+ writeAttr(out, ATTR_ACTIVITY, si.getActivityComponent());
// writeAttr(out, "icon", si.getIcon()); // We don't save it.
- writeAttr(out, "title", si.getTitle());
- writeAttr(out, "intent", si.getIntent());
- writeAttr(out, "weight", si.getWeight());
- writeAttr(out, "timestamp", si.getLastChangedTimestamp());
- writeAttr(out, "flags", si.getFlags());
- writeAttr(out, "icon-res", si.getIconResourceId());
- writeAttr(out, "bitmap-path", si.getBitmapPath());
+ writeAttr(out, ATTR_TITLE, si.getTitle());
+ writeAttr(out, ATTR_INTENT, si.getIntentNoExtras());
+ writeAttr(out, ATTR_WEIGHT, si.getWeight());
+ writeAttr(out, ATTR_TIMESTAMP, si.getLastChangedTimestamp());
+ writeAttr(out, ATTR_FLAGS, si.getFlags());
+ writeAttr(out, ATTR_ICON_RES, si.getIconResourceId());
+ writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath());
- writeTagExtra(out, "intent-extras", si.getIntentPersistableExtras());
- writeTagExtra(out, "extras", si.getExtras());
+ writeTagExtra(out, TAG_INTENT_EXTRAS, si.getIntentPersistableExtras());
+ writeTagExtra(out, TAG_EXTRAS, si.getExtras());
- out.endTag(null, "shortcut");
+ out.endTag(null, TAG_SHORTCUT);
}
private static IOException throwForInvalidTag(int depth, String tag) throws IOException {
@@ -710,24 +911,27 @@
}
case 2: {
switch (tag) {
- case "package":
- packageName = parseStringAttribute(parser, "name");
- shortcuts = new PackageShortcuts();
+ case TAG_PACKAGE:
+ packageName = parseStringAttribute(parser, ATTR_NAME);
+ shortcuts = new PackageShortcuts(userId, packageName);
ret.put(packageName, shortcuts);
shortcuts.mDynamicShortcutCount =
- (int) parseLongAttribute(parser, "dynamic-count");
- shortcuts.mApiCallCountInner =
- (int) parseLongAttribute(parser, "call-count");
- shortcuts.mLastResetTime = parseLongAttribute(parser, "last-reset");
+ (int) parseLongAttribute(parser, ATTR_DYNAMIC_COUNT);
+ shortcuts.mApiCallCount =
+ (int) parseLongAttribute(parser, ATTR_CALL_COUNT);
+ shortcuts.mLastResetTime = parseLongAttribute(parser,
+ ATTR_LAST_RESET);
continue;
}
break;
}
case 3: {
switch (tag) {
- case "shortcut":
+ case TAG_SHORTCUT:
final ShortcutInfo si = parseShortcut(parser, packageName);
+
+ // Don't use addShortcut(), we don't need to save the icon.
shortcuts.mShortcuts.put(si.getId(), si);
continue;
}
@@ -760,15 +964,15 @@
int iconRes;
String bitmapPath;
- id = parseStringAttribute(parser, "id");
- activityComponent = parseComponentNameAttribute(parser, "activity");
- title = parseStringAttribute(parser, "title");
- intent = parseIntentAttribute(parser, "intent");
- weight = (int) parseLongAttribute(parser, "weight");
- lastChangedTimestamp = (int) parseLongAttribute(parser, "timestamp");
- flags = (int) parseLongAttribute(parser, "flags");
- iconRes = (int) parseLongAttribute(parser, "icon-res");
- bitmapPath = parseStringAttribute(parser, "bitmap-path");
+ id = parseStringAttribute(parser, ATTR_ID);
+ activityComponent = parseComponentNameAttribute(parser, ATTR_ACTIVITY);
+ title = parseStringAttribute(parser, ATTR_TITLE);
+ intent = parseIntentAttribute(parser, ATTR_INTENT);
+ weight = (int) parseLongAttribute(parser, ATTR_WEIGHT);
+ lastChangedTimestamp = (int) parseLongAttribute(parser, ATTR_TIMESTAMP);
+ flags = (int) parseLongAttribute(parser, ATTR_FLAGS);
+ iconRes = (int) parseLongAttribute(parser, ATTR_ICON_RES);
+ bitmapPath = parseStringAttribute(parser, ATTR_BITMAP_PATH);
final int outerDepth = parser.getDepth();
int type;
@@ -784,10 +988,10 @@
depth, type, tag));
}
switch (tag) {
- case "intent-extras":
+ case TAG_INTENT_EXTRAS:
intentPersistableExtras = PersistableBundle.restoreFromXml(parser);
continue;
- case "extras":
+ case TAG_EXTRAS:
extras = PersistableBundle.restoreFromXml(parser);
continue;
}
@@ -875,7 +1079,7 @@
final ArrayMap<String, PackageShortcuts> userPackages = getUserShortcutsLocked(userId);
PackageShortcuts shortcuts = userPackages.get(packageName);
if (shortcuts == null) {
- shortcuts = new PackageShortcuts();
+ shortcuts = new PackageShortcuts(userId, packageName);
userPackages.put(packageName, shortcuts);
}
return shortcuts;
@@ -883,6 +1087,195 @@
// === Caller validation ===
+ void removeIcon(@UserIdInt int userId, ShortcutInfo shortcut) {
+ if (shortcut.getBitmapPath() != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Removing " + shortcut.getBitmapPath());
+ }
+ new File(shortcut.getBitmapPath()).delete();
+
+ shortcut.setBitmapPath(null);
+ shortcut.setIconResourceId(0);
+ shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES);
+ }
+ }
+
+ @VisibleForTesting
+ static class FileOutputStreamWithPath extends FileOutputStream {
+ private final File mFile;
+
+ public FileOutputStreamWithPath(File file) throws FileNotFoundException {
+ super(file);
+ mFile = file;
+ }
+
+ public File getFile() {
+ return mFile;
+ }
+ }
+
+ /**
+ * Build the cached bitmap filename for a shortcut icon.
+ *
+ * The filename will be based on the ID, except certain characters will be escaped.
+ */
+ @VisibleForTesting
+ FileOutputStreamWithPath openIconFileForWrite(@UserIdInt int userId, ShortcutInfo shortcut)
+ throws IOException {
+ final File packagePath = new File(getUserBitmapFilePath(userId),
+ shortcut.getPackageName());
+ if (!packagePath.isDirectory()) {
+ packagePath.mkdirs();
+ if (!packagePath.isDirectory()) {
+ throw new IOException("Unable to create directory " + packagePath);
+ }
+ SELinux.restorecon(packagePath);
+ }
+
+ final String baseName = String.valueOf(injectCurrentTimeMillis());
+ for (int suffix = 0;; suffix++) {
+ final String filename = (suffix == 0 ? baseName : baseName + "_" + suffix) + ".png";
+ final File file = new File(packagePath, filename);
+ if (!file.exists()) {
+ if (DEBUG) {
+ Slog.d(TAG, "Saving icon to " + file.getAbsolutePath());
+ }
+ return new FileOutputStreamWithPath(file);
+ }
+ }
+ }
+
+ void saveIconAndFixUpShortcut(@UserIdInt int userId, ShortcutInfo shortcut) {
+ if (shortcut.hasIconFile() || shortcut.hasIconResource()) {
+ return;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ // Clear icon info on the shortcut.
+ shortcut.setIconResourceId(0);
+ shortcut.setBitmapPath(null);
+
+ final Icon icon = shortcut.getIcon();
+ if (icon == null) {
+ return; // has no icon
+ }
+
+ Bitmap bitmap = null;
+ try {
+ switch (icon.getType()) {
+ case Icon.TYPE_RESOURCE: {
+ injectValidateIconResPackage(shortcut, icon);
+
+ shortcut.setIconResourceId(icon.getResId());
+ shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES);
+ return;
+ }
+ case Icon.TYPE_BITMAP: {
+ bitmap = icon.getBitmap();
+ break;
+ }
+ case Icon.TYPE_URI: {
+ final Uri uri = ContentProvider.maybeAddUserId(icon.getUri(), userId);
+
+ try (InputStream is = mContext.getContentResolver().openInputStream(uri)) {
+
+ bitmap = BitmapFactory.decodeStream(is);
+
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to load icon from " + uri);
+ return;
+ }
+ break;
+ }
+ default:
+ // This shouldn't happen because we've already validated the icon, but
+ // just in case.
+ throw ShortcutInfo.getInvalidIconException();
+ }
+ if (bitmap == null) {
+ Slog.e(TAG, "Null bitmap detected");
+ return;
+ }
+ // Shrink and write to the file.
+ File path = null;
+ try {
+ final FileOutputStreamWithPath out = openIconFileForWrite(userId, shortcut);
+ try {
+ path = out.getFile();
+
+ shrinkBitmap(bitmap, mMaxIconDimension)
+ .compress(mIconPersistFormat, mIconPersistQuality, out);
+
+ shortcut.setBitmapPath(out.getFile().getAbsolutePath());
+ shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ } catch (IOException|RuntimeException e) {
+ // STOPSHIP Change wtf to e
+ Slog.wtf(ShortcutService.TAG, "Unable to write bitmap to file", e);
+ if (path != null && path.exists()) {
+ path.delete();
+ }
+ }
+ } finally {
+ if (bitmap != null) {
+ bitmap.recycle();
+ }
+ // Once saved, we won't use the original icon information, so null it out.
+ shortcut.clearIcon();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // Unfortunately we can't do this check in unit tests because we fake creator package names,
+ // so override in unit tests.
+ // TODO CTS this case.
+ void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
+ if (!shortcut.getPackageName().equals(icon.getResPackage())) {
+ throw new IllegalArgumentException(
+ "Icon resource must reside in shortcut owner package");
+ }
+ }
+
+ @VisibleForTesting
+ static Bitmap shrinkBitmap(Bitmap in, int maxSize) {
+ // Original width/height.
+ final int ow = in.getWidth();
+ final int oh = in.getHeight();
+ if ((ow <= maxSize) && (oh <= maxSize)) {
+ if (DEBUG) {
+ Slog.d(TAG, String.format("Icon size %dx%d, no need to shrink", ow, oh));
+ }
+ return in;
+ }
+ final int longerDimension = Math.max(ow, oh);
+
+ // New width and height.
+ final int nw = ow * maxSize / longerDimension;
+ final int nh = oh * maxSize / longerDimension;
+ if (DEBUG) {
+ Slog.d(TAG, String.format("Icon size %dx%d, shrinking to %dx%d",
+ ow, oh, nw, nh));
+ }
+
+ final Bitmap scaledBitmap = Bitmap.createBitmap(nw, nh, Bitmap.Config.ARGB_8888);
+ final Canvas c = new Canvas(scaledBitmap);
+
+ final RectF dst = new RectF(0, 0, nw, nh);
+
+ c.drawBitmap(in, /*src=*/ null, dst, /* paint =*/ null);
+
+ in.recycle();
+
+ return scaledBitmap;
+ }
+
+ // === Caller validation ===
+
private boolean isCallerSystem() {
final int callingUid = injectBinderCallingUid();
return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
@@ -915,31 +1308,21 @@
if (UserHandle.getUserId(callingUid) != userId) {
throw new SecurityException("Invalid user-ID");
}
- verifyCallingPackage(packageName);
- }
-
- private void verifyCallingPackage(@NonNull String packageName) {
- Preconditions.checkStringNotEmpty(packageName, "packageName");
-
- if (isCallerSystem()) {
- return; // no check
- }
-
- if (injectGetPackageUid(packageName) == injectBinderCallingUid()) {
+ if (injectGetPackageUid(packageName, userId) == injectBinderCallingUid()) {
return; // Caller is valid.
}
throw new SecurityException("Caller UID= doesn't own " + packageName);
}
// Test overrides it.
- int injectGetPackageUid(String packageName) {
+ int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
try {
// TODO Is MATCH_UNINSTALLED_PACKAGES correct to get SD card app info?
- return mContext.getPackageManager().getPackageUid(packageName,
+ return mContext.getPackageManager().getPackageUidAsUser(packageName,
PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE
- | PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
} catch (NameNotFoundException e) {
return -1;
}
@@ -983,8 +1366,10 @@
* - Make sure the intent's extras are persistable, and them to set
* {@link ShortcutInfo#mIntentPersistableExtras}. Also clear its extras.
* - Clear flags.
+ *
+ * TODO Detailed unit tests
*/
- private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut) {
+ private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
Preconditions.checkNotNull(shortcut, "Null shortcut detected");
if (shortcut.getActivityComponent() != null) {
Preconditions.checkState(
@@ -993,24 +1378,60 @@
"Activity package name mismatch");
}
- shortcut.enforceMandatoryFields();
-
- final Intent intent = shortcut.getIntent();
- final Bundle intentExtras = intent.getExtras();
- if (intentExtras != null && intentExtras.size() > 0) {
- intent.replaceExtras((Bundle) null);
-
- // PersistableBundle's constructor will throw IllegalArgumentException if original
- // extras contain something not persistable.
- shortcut.setIntentPersistableExtras(new PersistableBundle(intentExtras));
+ if (!forUpdate) {
+ shortcut.enforceMandatoryFields();
+ }
+ if (shortcut.getIcon() != null) {
+ ShortcutInfo.validateIcon(shortcut.getIcon());
}
- // TODO Save the icon
- shortcut.setIcon(null);
+ validateForXml(shortcut.getId());
+ validateForXml(shortcut.getTitle());
+ validatePersistableBundleForXml(shortcut.getIntentPersistableExtras());
+ validatePersistableBundleForXml(shortcut.getExtras());
shortcut.setFlags(0);
}
+ // KXmlSerializer is strict and doesn't allow certain characters, so we disallow those
+ // characters.
+
+ private static void validatePersistableBundleForXml(PersistableBundle b) {
+ if (b == null || b.size() == 0) {
+ return;
+ }
+ for (String key : b.keySet()) {
+ validateForXml(key);
+ final Object value = b.get(key);
+ if (value == null) {
+ continue;
+ } else if (value instanceof String) {
+ validateForXml((String) value);
+ } else if (value instanceof String[]) {
+ for (String v : (String[]) value) {
+ validateForXml(v);
+ }
+ } else if (value instanceof PersistableBundle) {
+ validatePersistableBundleForXml((PersistableBundle) value);
+ }
+ }
+ }
+
+ private static void validateForXml(String s) {
+ if (TextUtils.isEmpty(s)) {
+ return;
+ }
+ for (int i = s.length() - 1; i >= 0; i--) {
+ if (!isAllowedInXml(s.charAt(i))) {
+ throw new IllegalArgumentException("Unsupported character detected in: " + s);
+ }
+ }
+ }
+
+ private static boolean isAllowedInXml(char c) {
+ return (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd);
+ }
+
// === APIs ===
@Override
@@ -1032,11 +1453,11 @@
// Validate the shortcuts.
for (int i = 0; i < size; i++) {
- fixUpIncomingShortcutInfo(newShortcuts.get(i));
+ fixUpIncomingShortcutInfo(newShortcuts.get(i), /* forUpdate= */ false);
}
// First, remove all un-pinned; dynamic shortcuts
- ps.deleteAllDynamicShortcuts();
+ ps.deleteAllDynamicShortcuts(this);
// Then, add/update all. We need to make sure to take over "pinned" flag.
for (int i = 0; i < size; i++) {
@@ -1046,7 +1467,6 @@
}
}
userPackageChanged(packageName, userId);
-
return true;
}
@@ -1056,15 +1476,34 @@
verifyCaller(packageName, userId);
final List<ShortcutInfo> newShortcuts = (List<ShortcutInfo>) shortcutInfoList.getList();
+ final int size = newShortcuts.size();
synchronized (mLock) {
+ final PackageShortcuts ps = getPackageShortcutsLocked(packageName, userId);
- if (true) {
- throw new RuntimeException("not implemented yet");
+ // Throttling.
+ if (!ps.tryApiCall(this)) {
+ return false;
}
- // TODO Similar to setDynamicShortcuts, but don't add new ones, and don't change flags.
- // Update non-null fields only.
+ for (int i = 0; i < size; i++) {
+ final ShortcutInfo source = newShortcuts.get(i);
+ fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);
+
+ final ShortcutInfo target = ps.findShortcutById(source.getId());
+ if (target != null) {
+ final boolean replacingIcon = (source.getIcon() != null);
+ if (replacingIcon) {
+ removeIcon(userId, target);
+ }
+
+ target.copyNonNullFieldsFrom(source);
+
+ if (replacingIcon) {
+ saveIconAndFixUpShortcut(userId, target);
+ }
+ }
+ }
}
userPackageChanged(packageName, userId);
@@ -1085,7 +1524,7 @@
}
// Validate the shortcut.
- fixUpIncomingShortcutInfo(newShortcut);
+ fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
// Add it.
newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
@@ -1103,7 +1542,7 @@
Preconditions.checkStringNotEmpty(shortcutId, "shortcutId must be provided");
synchronized (mLock) {
- getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(shortcutId);
+ getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this, shortcutId);
}
userPackageChanged(packageName, userId);
}
@@ -1113,7 +1552,7 @@
verifyCaller(packageName, userId);
synchronized (mLock) {
- getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts();
+ getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts(this);
}
userPackageChanged(packageName, userId);
}
@@ -1177,6 +1616,13 @@
}
}
+ @Override
+ public int getIconMaxDimensions(String packageName, int userId) throws RemoteException {
+ synchronized (mLock) {
+ return mMaxIconDimension;
+ }
+ }
+
/**
* Reset all throttling, for developer options and command line. Only system/shell can call it.
*/
@@ -1193,6 +1639,7 @@
mRawLastResetTime = injectCurrentTimeMillis();
}
scheduleSaveBaseState();
+ Slog.i(TAG, "ShortcutManager: throttling counter reset");
}
/**
@@ -1217,7 +1664,7 @@
} else {
final ArrayMap<String, PackageShortcuts> packages =
getUserShortcutsLocked(userId);
- for (int i = 0; i < packages.size(); i++) {
+ for (int i = packages.size() - 1; i >= 0; i--) {
getShortcutsInnerLocked(
packages.keyAt(i),
changedSince, componentName, queryFlags, userId, ret, cloneFlag);
@@ -1274,32 +1721,24 @@
Preconditions.checkNotNull(shortcutIds, "shortcutIds");
synchronized (mLock) {
- getPackageShortcutsLocked(packageName, userId).pinAll(shortcutIds);
+ getPackageShortcutsLocked(packageName, userId).replacePinned(
+ ShortcutService.this, callingPackage, shortcutIds);
}
userPackageChanged(packageName, userId);
}
@Override
public Intent createShortcutIntent(@NonNull String callingPackage,
- @NonNull ShortcutInfo shortcut, int userId) {
+ @NonNull String packageName, @NonNull String shortcutId, int userId) {
// Calling permission must be checked by LauncherAppsImpl.
- Preconditions.checkNotNull(shortcut, "shortcut");
+ Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
+ Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
synchronized (mLock) {
final ShortcutInfo fullShortcut =
- getPackageShortcutsLocked(shortcut.getPackageName(), userId)
- .getShortcuts().get(shortcut.getId());
- if (fullShortcut == null) {
- return null;
- } else {
- final Intent intent = fullShortcut.getIntent();
- final PersistableBundle extras = fullShortcut.getIntentPersistableExtras();
- if (extras != null) {
- intent.replaceExtras(new Bundle(extras));
- }
-
- return intent;
- }
+ getPackageShortcutsLocked(packageName, userId)
+ .findShortcutById(shortcutId);
+ return fullShortcut == null ? null : fullShortcut.getIntent();
}
}
@@ -1309,6 +1748,41 @@
mListeners.add(Preconditions.checkNotNull(listener));
}
}
+
+ @Override
+ public int getShortcutIconResId(@NonNull String callingPackage,
+ @NonNull ShortcutInfo shortcut, int userId) {
+ Preconditions.checkNotNull(shortcut, "shortcut");
+
+ synchronized (mLock) {
+ final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
+ shortcut.getPackageName(), userId).findShortcutById(shortcut.getId());
+ return (shortcutInfo != null && shortcutInfo.hasIconResource())
+ ? shortcutInfo.getIconResourceId() : 0;
+ }
+ }
+
+ @Override
+ public ParcelFileDescriptor getShortcutIconFd(@NonNull String callingPackage,
+ @NonNull ShortcutInfo shortcut, int userId) {
+ Preconditions.checkNotNull(shortcut, "shortcut");
+
+ synchronized (mLock) {
+ final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
+ shortcut.getPackageName(), userId).findShortcutById(shortcut.getId());
+ if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
+ return null;
+ }
+ try {
+ return ParcelFileDescriptor.open(
+ new File(shortcutInfo.getBitmapPath()),
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ Slog.e(TAG, "Icon file not found: " + shortcutInfo.getBitmapPath());
+ return null;
+ }
+ }
+ }
}
// === Dump ===
@@ -1335,30 +1809,38 @@
pw.print(now);
pw.print("] ");
pw.print(formatTime(now));
+
pw.print(" Raw last reset: [");
pw.print(mRawLastResetTime);
pw.print("] ");
pw.print(formatTime(mRawLastResetTime));
final long last = getLastResetTimeLocked();
- final long next = getNextResetTimeLocked();
pw.print(" Last reset: [");
pw.print(last);
pw.print("] ");
pw.print(formatTime(last));
+ final long next = getNextResetTimeLocked();
pw.print(" Next reset: [");
pw.print(next);
pw.print("] ");
pw.print(formatTime(next));
pw.println();
+ pw.print(" Max icon dim: ");
+ pw.print(mMaxIconDimension);
+ pw.print(" Icon format: ");
+ pw.print(mIconPersistFormat);
+ pw.print(" Icon quality: ");
+ pw.print(mIconPersistQuality);
+ pw.println();
+
pw.println();
for (int i = 0; i < mShortcuts.size(); i++) {
dumpUserLocked(pw, mShortcuts.keyAt(i));
}
-
}
}
@@ -1378,8 +1860,8 @@
}
private void dumpPackageLocked(PrintWriter pw, int userId, String packageName) {
- final PackageShortcuts shortcuts = mShortcuts.get(userId).get(packageName);
- if (shortcuts == null) {
+ final PackageShortcuts packageShortcuts = mShortcuts.get(userId).get(packageName);
+ if (packageShortcuts == null) {
return;
}
@@ -1388,22 +1870,38 @@
pw.println();
pw.print(" Calls: ");
- pw.print(shortcuts.getApiCallCount(this));
+ pw.print(packageShortcuts.getApiCallCount(this));
pw.println();
// This should be after getApiCallCount(), which may update it.
pw.print(" Last reset: [");
- pw.print(shortcuts.mLastResetTime);
+ pw.print(packageShortcuts.mLastResetTime);
pw.print("] ");
- pw.print(formatTime(shortcuts.mLastResetTime));
+ pw.print(formatTime(packageShortcuts.mLastResetTime));
pw.println();
pw.println(" Shortcuts:");
- final int size = shortcuts.getShortcuts().size();
+ long totalBitmapSize = 0;
+ final ArrayMap<String, ShortcutInfo> shortcuts = packageShortcuts.mShortcuts;
+ final int size = shortcuts.size();
for (int i = 0; i < size; i++) {
+ final ShortcutInfo si = shortcuts.valueAt(i);
pw.print(" ");
- pw.println(shortcuts.getShortcuts().valueAt(i).toInsecureString());
+ pw.println(si.toInsecureString());
+ if (si.hasIconFile()) {
+ final long len = new File(si.getBitmapPath()).length();
+ pw.print(" ");
+ pw.print("bitmap size=");
+ pw.println(len);
+
+ totalBitmapSize += len;
+ }
}
+ pw.print(" Total bitmap size: ");
+ pw.print(totalBitmapSize);
+ pw.print(" (");
+ pw.print(Formatter.formatFileSize(mContext, totalBitmapSize));
+ pw.println(")");
}
private static String formatTime(long time) {
@@ -1433,14 +1931,27 @@
return handleDefaultCommands(cmd);
}
final PrintWriter pw = getOutPrintWriter();
- switch(cmd) {
+ int ret = 1;
+ switch (cmd) {
case "reset-package-throttling":
- return handleResetPackageThrottling();
+ ret = handleResetPackageThrottling();
+ break;
case "reset-throttling":
- return handleResetThrottling();
+ ret = handleResetThrottling();
+ break;
+ case "override-config":
+ ret = handleOverrideConfig();
+ break;
+ case "reset-config":
+ ret = handleResetConfig();
+ break;
default:
return handleDefaultCommands(cmd);
}
+ if (ret == 0) {
+ pw.println("Success");
+ }
+ return ret;
}
@Override
@@ -1454,6 +1965,12 @@
pw.println("cmd shortcut reset-throttling");
pw.println(" Reset throttling for all packages and users");
pw.println();
+ pw.println("cmd shortcut override-config CONFIG");
+ pw.println(" Override the configuration for testing (will last until reboot)");
+ pw.println();
+ pw.println("cmd shortcut reset-config");
+ pw.println(" Reset the configuration set with \"update-config\"");
+ pw.println();
}
private int handleResetThrottling() {
@@ -1485,6 +2002,26 @@
return 0;
}
+
+ private int handleOverrideConfig() {
+ final PrintWriter pw = getOutPrintWriter();
+ final String config = getNextArgRequired();
+
+ synchronized (mLock) {
+ if (!updateConfigurationLocked(config)) {
+ pw.println("override-config failed. See logcat for details.");
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ private int handleResetConfig() {
+ synchronized (mLock) {
+ loadConfigurationLocked();
+ }
+ return 0;
+ }
}
// === Unit test support ===
@@ -1504,7 +2041,16 @@
}
File injectUserDataPath(@UserIdInt int userId) {
- return new File(Environment.getDataSystemDeDirectory(userId), DIRECTORY_PER_USER);
+ return new File(Environment.getDataSystemCeDirectory(userId), DIRECTORY_PER_USER);
+ }
+
+ @VisibleForTesting
+ boolean injectIsLowRamDevice() {
+ return ActivityManager.isLowRamDeviceStatic();
+ }
+
+ File getUserBitmapFilePath(@UserIdInt int userId) {
+ return new File(injectUserDataPath(userId), DIRECTORY_BITMAPS);
}
@VisibleForTesting
@@ -1513,17 +2059,32 @@
}
@VisibleForTesting
- void setMaxDynamicShortcutsForTest(int max) {
- mMaxDynamicShortcuts = max;
+ int getMaxDynamicShortcutsForTest() {
+ return mMaxDynamicShortcuts;
}
@VisibleForTesting
- void setMaxDailyUpdatesForTest(int max) {
- mMaxDailyUpdates = max;
+ int getMaxDailyUpdatesForTest() {
+ return mMaxDailyUpdates;
}
@VisibleForTesting
- public void setResetIntervalForTest(long interval) {
- mResetInterval = interval;
+ long getResetIntervalForTest() {
+ return mResetInterval;
+ }
+
+ @VisibleForTesting
+ int getMaxIconDimensionForTest() {
+ return mMaxIconDimension;
+ }
+
+ @VisibleForTesting
+ CompressFormat getIconPersistFormatForTest() {
+ return mIconPersistFormat;
+ }
+
+ @VisibleForTesting
+ int getIconPersistQualityForTest() {
+ return mIconPersistQuality;
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 83a5ef5..0cd69c4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -28,6 +28,8 @@
import static android.view.WindowManager.DOCKED_TOP;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
+import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
@@ -209,6 +211,13 @@
static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP = 0;
static final int SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME = 1;
+ // Controls navigation bar opacity depending on which workspace stacks are currently
+ // visible.
+ // Nav bar is always opaque when either the freeform stack or docked stack is visible.
+ static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
+ // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
+ static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
+
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
static final int APPLICATION_PANEL_SUBLAYER = 1;
@@ -537,7 +546,7 @@
boolean mForceStatusBar;
boolean mForceStatusBarFromKeyguard;
private boolean mForceStatusBarTransparent;
- boolean mForceNavBarOpaque;
+ int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
boolean mHideLockScreen;
boolean mForcingShowNavBar;
int mForcingShowNavBarLayer;
@@ -1239,7 +1248,7 @@
+ SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
mScreenshotChordVolumeDownKeyConsumed = true;
cancelPendingPowerKeyAction();
-
+ mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
}
}
@@ -1269,12 +1278,20 @@
}
};
- private final Runnable mScreenshotRunnable = new Runnable() {
+ private class ScreenshotRunnable implements Runnable {
+ private int mScreenshotType = TAKE_SCREENSHOT_FULLSCREEN;
+
+ public void setScreenshotType(int screenshotType) {
+ mScreenshotType = screenshotType;
+ }
+
@Override
public void run() {
- takeScreenshot();
+ takeScreenshot(mScreenshotType);
}
- };
+ }
+
+ private final ScreenshotRunnable mScreenshotRunnable = new ScreenshotRunnable();
@Override
public void showGlobalActions() {
@@ -1719,8 +1736,8 @@
mShortPressWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
}
- mForceNavBarOpaque = res.getBoolean(
- com.android.internal.R.bool.config_forceNavBarAlwaysOpaque);
+ mNavBarOpacityMode = res.getInteger(
+ com.android.internal.R.integer.config_navBarOpacityMode);
}
@Override
@@ -2304,29 +2321,33 @@
case TYPE_NAVIGATION_BAR_PANEL:
// some panels (e.g. search) need to show on top of the navigation bar
return 22;
+ case TYPE_SCREENSHOT:
+ // screenshot selection layer shouldn't go above system error, but it should cover
+ // navigation bars at the very least.
+ return 23;
case TYPE_SYSTEM_ERROR:
// system-level error dialogs
- return 23;
+ return 24;
case TYPE_MAGNIFICATION_OVERLAY:
// used to highlight the magnified portion of a display
- return 24;
+ return 25;
case TYPE_DISPLAY_OVERLAY:
// used to simulate secondary display devices
- return 25;
+ return 26;
case TYPE_DRAG:
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
- return 26;
+ return 27;
case TYPE_ACCESSIBILITY_OVERLAY:
// overlay put by accessibility services to intercept user interaction
- return 27;
- case TYPE_SECURE_SYSTEM_OVERLAY:
return 28;
- case TYPE_BOOT_PROGRESS:
+ case TYPE_SECURE_SYSTEM_OVERLAY:
return 29;
+ case TYPE_BOOT_PROGRESS:
+ return 30;
case TYPE_POINTER:
// the (mouse) pointer layer
- return 30;
+ return 31;
}
Log.e(TAG, "Unknown window type: " + type);
return 2;
@@ -3026,6 +3047,15 @@
}
}
}
+ } else if (keyCode == KeyEvent.KEYCODE_S && event.isMetaPressed()
+ && event.isCtrlPressed()) {
+ if (down && repeatCount == 0) {
+ int type = event.isShiftPressed() ? TAKE_SCREENSHOT_SELECTED_REGION
+ : TAKE_SCREENSHOT_FULLSCREEN;
+ mScreenshotRunnable.setScreenshotType(type);
+ mHandler.post(mScreenshotRunnable);
+ return -1;
+ }
} else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
if (down) {
if (repeatCount == 0) {
@@ -3073,6 +3103,7 @@
}
} else if (keyCode == KeyEvent.KEYCODE_SYSRQ) {
if (down && repeatCount == 0) {
+ mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
mHandler.post(mScreenshotRunnable);
}
return -1;
@@ -4402,9 +4433,11 @@
"Laying out navigation bar window: (%d,%d - %d,%d)",
pf.left, pf.top, pf.right, pf.bottom));
} else if ((attrs.type == TYPE_SECURE_SYSTEM_OVERLAY
- || attrs.type == TYPE_BOOT_PROGRESS)
+ || attrs.type == TYPE_BOOT_PROGRESS
+ || attrs.type == TYPE_SCREENSHOT)
&& ((fl & FLAG_FULLSCREEN) != 0)) {
- // Fullscreen secure system overlays get what they ask for.
+ // Fullscreen secure system overlays get what they ask for. Screenshot region
+ // selection overlay should also expand to full screen.
pf.left = df.left = of.left = cf.left = mOverscanScreenLeft;
pf.top = df.top = of.top = cf.top = mOverscanScreenTop;
pf.right = df.right = of.right = cf.right = mOverscanScreenLeft
@@ -5159,7 +5192,7 @@
};
// Assume this is called from the Handler thread.
- private void takeScreenshot() {
+ private void takeScreenshot(final int screenshotType) {
synchronized (mScreenshotLock) {
if (mScreenshotConnection != null) {
return;
@@ -5176,7 +5209,7 @@
return;
}
Messenger messenger = new Messenger(service);
- Message msg = Message.obtain(null, 1);
+ Message msg = Message.obtain(null, screenshotType);
final ServiceConnection myConn = this;
Handler h = new Handler(mHandler.getLooper()) {
@Override
@@ -7067,7 +7100,7 @@
// is visible but also when we are resizing for the transitions when docked stack
// visibility changes.
mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
- final boolean forceOpaqueSystemBars = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
+ final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
// apply translucent bar vis flags
WindowState transWin = isStatusBarKeyguard() && !mHideLockScreen
@@ -7092,14 +7125,11 @@
}
if ((!areTranslucentBarsAllowed() && transWin != mStatusBar)
- || forceOpaqueSystemBars) {
- vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT
- | View.SYSTEM_UI_TRANSPARENT);
+ || forceOpaqueStatusBar) {
+ vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
}
- if (mForceNavBarOpaque) {
- vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
- }
+ vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing);
if (mForceWindowDrawsStatusBarBackground) {
vis |= View.STATUS_BAR_TRANSPARENT;
@@ -7173,6 +7203,41 @@
return vis;
}
+ /**
+ * @return the current visibility flags with the nav-bar opacity related flags toggled based
+ * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
+ */
+ private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
+ boolean freeformStackVisible, boolean isDockedDividerResizing) {
+ if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
+ if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
+ visibility = setNavBarOpaqueFlag(visibility);
+ }
+ } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
+ if (isDockedDividerResizing) {
+ visibility = setNavBarOpaqueFlag(visibility);
+ } else if (freeformStackVisible) {
+ visibility = setNavBarTranslucentFlag(visibility);
+ } else {
+ visibility = setNavBarOpaqueFlag(visibility);
+ }
+ }
+
+ if (!areTranslucentBarsAllowed()) {
+ visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
+ }
+ return visibility;
+ }
+
+ private int setNavBarOpaqueFlag(int visibility) {
+ return visibility &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
+ }
+
+ private int setNavBarTranslucentFlag(int visibility) {
+ visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
+ return visibility |= View.NAVIGATION_BAR_TRANSLUCENT;
+ }
+
private void clearClearableFlagsLw() {
int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
if (newVal != mResettingSystemUiFlags) {
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index e5c5b2bc..858f7c7 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -81,6 +81,7 @@
private boolean mBound;
private long mScheduledRestartUptimeMillis;
private long mMaximumTimeToLock; // from DevicePolicyManager
+ private boolean mPendingSuccessfulUnlock = false;
// Trust state
private boolean mTrusted;
@@ -234,6 +235,11 @@
setCallback(mCallback);
updateDevicePolicyFeatures();
+ if (mPendingSuccessfulUnlock) {
+ onUnlockAttempt(true);
+ mPendingSuccessfulUnlock = false;
+ }
+
if (mTrustManagerService.isDeviceLockedInner(mUserId)) {
onDeviceLocked();
} else {
@@ -302,7 +308,11 @@
*/
public void onUnlockAttempt(boolean successful) {
try {
- if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful);
+ if (mTrustAgentService != null) {
+ mTrustAgentService.onUnlockAttempt(successful);
+ } else {
+ mPendingSuccessfulUnlock = successful;
+ }
} catch (RemoteException e) {
onError(e);
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index b54e866..984fb76 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -19,7 +19,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
import com.android.server.SystemService;
import org.xmlpull.v1.XmlPullParser;
@@ -104,7 +103,7 @@
private static final int MSG_SET_DEVICE_LOCKED = 10;
private static final int MSG_FLUSH_TRUST_USUALLY_MANAGED = 11;
- public static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
+ private static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
@@ -136,13 +135,7 @@
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
mLockPatternUtils = new LockPatternUtils(context);
-
- mStrongAuthTracker = new StrongAuthTracker(context) {
- @Override
- public void onStrongAuthRequiredChanged(int userId) {
- refreshAgentList(userId);
- }
- };
+ mStrongAuthTracker = new StrongAuthTracker(context);
}
@Override
@@ -231,24 +224,24 @@
TRUST_USUALLY_MANAGED_FLUSH_DELAY);
}
- void refreshAgentList(int userId) {
- if (DEBUG) Slog.d(TAG, "refreshAgentList()");
+ void refreshAgentList(int userIdOrAll) {
+ if (DEBUG) Slog.d(TAG, "refreshAgentList(" + userIdOrAll + ")");
if (!mTrustAgentsCanRun) {
return;
}
- if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_SYSTEM) {
- Log.e(TAG, "refreshAgentList(userId=" + userId + "): Invalid user handle,"
+ if (userIdOrAll != UserHandle.USER_ALL && userIdOrAll < UserHandle.USER_SYSTEM) {
+ Log.e(TAG, "refreshAgentList(userId=" + userIdOrAll + "): Invalid user handle,"
+ " must be USER_ALL or a specific user.", new Throwable("here"));
- userId = UserHandle.USER_ALL;
+ userIdOrAll = UserHandle.USER_ALL;
}
PackageManager pm = mContext.getPackageManager();
List<UserInfo> userInfos;
- if (userId == UserHandle.USER_ALL) {
+ if (userIdOrAll == UserHandle.USER_ALL) {
userInfos = mUserManager.getUsers(true /* excludeDying */);
} else {
userInfos = new ArrayList<>();
- userInfos.add(mUserManager.getUserInfo(userId));
+ userInfos.add(mUserManager.getUserInfo(userIdOrAll));
}
LockPatternUtils lockPatternUtils = mLockPatternUtils;
@@ -261,7 +254,7 @@
if (!userInfo.supportsSwitchToByUser()) continue;
if (!mActivityManager.isUserRunning(userInfo.id)) continue;
if (!lockPatternUtils.isSecure(userInfo.id)) continue;
- if (!mStrongAuthTracker.isTrustAllowedForUser(userInfo.id)) continue;
+ if (!mStrongAuthTracker.canAgentsRunForUser(userInfo.id)) continue;
DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager();
int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id);
final boolean disableTrustAgents =
@@ -302,7 +295,7 @@
boolean trustMayHaveChanged = false;
for (int i = 0; i < obsoleteAgents.size(); i++) {
AgentInfo info = obsoleteAgents.valueAt(i);
- if (userId == UserHandle.USER_ALL || userId == info.userId) {
+ if (userIdOrAll == UserHandle.USER_ALL || userIdOrAll == info.userId) {
if (info.agent.isManagingTrust()) {
trustMayHaveChanged = true;
}
@@ -312,10 +305,10 @@
}
if (trustMayHaveChanged) {
- if (userId == UserHandle.USER_ALL) {
+ if (userIdOrAll == UserHandle.USER_ALL) {
updateTrustAll();
} else {
- updateTrust(userId, 0);
+ updateTrust(userIdOrAll, 0);
}
}
}
@@ -578,6 +571,10 @@
}
private void dispatchUnlockAttempt(boolean successful, int userId) {
+ if (successful) {
+ mStrongAuthTracker.allowTrustFromUnlock(userId);
+ }
+
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo info = mActiveAgents.valueAt(i);
if (info.userId == userId) {
@@ -608,6 +605,10 @@
}
private void dispatchOnTrustChanged(boolean enabled, int userId, int flags) {
+ if (DEBUG) {
+ Log.i(TAG, "onTrustChanged(" + enabled + ", " + userId + ", 0x"
+ + Integer.toHexString(flags) + ")");
+ }
if (!enabled) flags = 0;
for (int i = 0; i < mTrustListeners.size(); i++) {
try {
@@ -623,6 +624,9 @@
}
private void dispatchOnTrustManagedChanged(boolean managed, int userId) {
+ if (DEBUG) {
+ Log.i(TAG, "onTrustManagedChanged(" + managed + ", " + userId + ")");
+ }
for (int i = 0; i < mTrustListeners.size(); i++) {
try {
mTrustListeners.get(i).onTrustManagedChanged(managed, userId);
@@ -980,4 +984,61 @@
null /* scheduler */);
}
}
+
+ private class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+
+ SparseBooleanArray mStartFromSuccessfulUnlock = new SparseBooleanArray();
+
+ public StrongAuthTracker(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStrongAuthRequiredChanged(int userId) {
+ mStartFromSuccessfulUnlock.delete(userId);
+
+ if (DEBUG) {
+ Log.i(TAG, "onStrongAuthRequiredChanged(" + userId + ") ->"
+ + " trustAllowed=" + isTrustAllowedForUser(userId)
+ + " agentsCanRun=" + canAgentsRunForUser(userId));
+ }
+
+ refreshAgentList(userId);
+
+ // The list of active trust agents may not have changed, if there was a previous call
+ // to allowTrustFromUnlock, so we update the trust here too.
+ updateTrust(userId, 0 /* flags */);
+ }
+
+ boolean canAgentsRunForUser(int userId) {
+ return mStartFromSuccessfulUnlock.get(userId)
+ || super.isTrustAllowedForUser(userId);
+ }
+
+ /**
+ * Temporarily suppress strong auth requirements for {@param userId} until strong auth
+ * changes again. Must only be called when we know about a successful unlock already
+ * before the underlying StrongAuthTracker.
+ *
+ * Note that this only changes whether trust agents can be started, not the actual trusted
+ * value.
+ */
+ void allowTrustFromUnlock(int userId) {
+ if (userId < UserHandle.USER_SYSTEM) {
+ throw new IllegalArgumentException("userId must be a valid user: " + userId);
+ }
+ boolean previous = canAgentsRunForUser(userId);
+ mStartFromSuccessfulUnlock.put(userId, true);
+
+ if (DEBUG) {
+ Log.i(TAG, "allowTrustFromUnlock(" + userId + ") ->"
+ + " trustAllowed=" + isTrustAllowedForUser(userId)
+ + " agentsCanRun=" + canAgentsRunForUser(userId));
+ }
+
+ if (canAgentsRunForUser(userId) != previous) {
+ refreshAgentList(userId);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 9c770e1..2db6b5d 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -190,7 +190,7 @@
userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
getContext().registerReceiver(mWebViewUpdatedReceiver, userAddedFilter);
- publishBinderService("webviewupdate", new BinderService());
+ publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
}
private static boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 676b90f..60b2e4a 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -148,9 +148,7 @@
boolean setBounds(
Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
SparseArray<Rect> taskTempInsetBounds) {
- if (!setBounds(stackBounds)) {
- return false;
- }
+ setBounds(stackBounds);
// Update bounds of containing tasks.
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -608,13 +606,6 @@
}
updateDisplayInfo(bounds);
-
- if (mStackId == DOCKED_STACK_ID) {
- // Attaching a docked stack to the display affects the size of all other static
- // stacks since the docked stack occupies a dedicated region on screen.
- // Resize existing static stacks so they are pushed to the side of the docked stack.
- resizeNonDockedStacks(!FULLSCREEN, mBounds);
- }
}
void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
@@ -723,36 +714,6 @@
DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
}
- /** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
- * based on the presence of a docked stack.
- * @param fullscreen If true the stacks will be resized to fullscreen, else they will be
- * resized to the appropriate size based on the presence of a docked stack.
- * @param dockedBounds Bounds of the docked stack.
- */
- private void resizeNonDockedStacks(boolean fullscreen, Rect dockedBounds) {
- // Not using mTmpRect because we are posting the object in a message.
- final Rect bounds = new Rect();
- mDisplayContent.getLogicalDisplayRect(bounds);
- if (!fullscreen) {
- final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
- == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
- getStackDockedModeBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds,
- mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
- }
-
- final int count = mService.mStackIdToStack.size();
- for (int i = 0; i < count; i++) {
- final TaskStack otherStack = mService.mStackIdToStack.valueAt(i);
- final int otherStackId = otherStack.mStackId;
- if (StackId.isResizeableByDockedStack(otherStackId)
- && !otherStack.mBounds.equals(bounds)) {
- mService.mH.sendMessage(
- mService.mH.obtainMessage(RESIZE_STACK, otherStackId,
- 1 /*allowResizeInDockedMode*/, fullscreen ? null : bounds));
- }
- }
- }
-
void resetDockedStackToMiddle() {
if (mStackId != DOCKED_STACK_ID) {
throw new IllegalStateException("Not a docked stack=" + this);
@@ -786,12 +747,6 @@
mService.mWindowPlacerLocked.requestTraversal();
}
- if (mStackId == DOCKED_STACK_ID) {
- // Docked stack was detached from the display, so we no longer need to restrict the
- // region of the screen other static stacks occupy. Go ahead and make them fullscreen.
- resizeNonDockedStacks(FULLSCREEN, null);
- }
-
close();
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 617d2b4..910788e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -780,9 +780,9 @@
Math.min(mStableFrame.bottom, frame.bottom));
}
- if (!windowsAreFloating) {
- // Windows from floating tasks (e.g. freeform, pinned) may be positioned outside
- // of the display frame, but that is not a reason to provide them with overscan insets.
+ if (fullscreenTask && !windowsAreFloating) {
+ // Windows that are not fullscreen 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),
@@ -2257,7 +2257,7 @@
// background.
return (mDisplayContent.mDividerControllerLocked.isResizing()
|| mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) &&
- !task.inFreeformWorkspace() && isVisibleLw();
+ !task.inFreeformWorkspace() && !isGoneForLayoutLw();
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 60ed497..5f67b7f 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1209,6 +1209,10 @@
static_cast<int32_t>(measurement->multipath_indicator));
SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+ SET_IF(!GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE,
+ PseudorangeRateCorrected,
+ true);
+
return object.get();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6ab4804..d218afc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1637,14 +1637,12 @@
}
// Still at the first stage of CryptKeeper double bounce, mOwners.hasDeviceOwner is
// always false at this point.
- if ("encrypted".equals(mInjector.systemPropertiesGet("ro.crypto.state"))
- && "trigger_restart_min_framework".equals(
- mInjector.systemPropertiesGet("vold.decrypt"))){
+ if (StorageManager.inCryptKeeperBounce()) {
return;
}
if (!TextUtils.isEmpty(mInjector.systemPropertiesGet(PROPERTY_DEVICE_OWNER_PRESENT))) {
- Slog.wtf(LOG_TAG, "Trying to set ro.device_owner, but it has already been set?");
+ Slog.w(LOG_TAG, "Trying to set ro.device_owner, but it has already been set?");
} else {
if (mOwners.hasDeviceOwner()) {
mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, "true");
@@ -4864,17 +4862,11 @@
* {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
*/
private int getEncryptionStatus() {
- String status = mInjector.systemPropertiesGet("ro.crypto.state", "unsupported");
- if ("encrypted".equalsIgnoreCase(status)) {
- final long token = mInjector.binderClearCallingIdentity();
- try {
- return LockPatternUtils.isDeviceEncrypted()
- ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
- : DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY;
- } finally {
- mInjector.binderRestoreCallingIdentity(token);
- }
- } else if ("unencrypted".equalsIgnoreCase(status)) {
+ if (!StorageManager.isNonDefaultBlockEncrypted()) {
+ return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY;
+ } else if (StorageManager.isEncrypted()) {
+ return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
+ } else if (StorageManager.isEncryptable()) {
return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
} else {
return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
@@ -8193,10 +8185,10 @@
}
@Override
- public String getWifiMacAddress() {
+ public String getWifiMacAddress(ComponentName admin) {
// Make sure caller has DO.
synchronized (this) {
- getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
}
final long ident = mInjector.binderClearCallingIdentity();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 59f8284a..e7daaa1 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -726,9 +726,6 @@
// Always start the Device Policy Manager, so that the API is compatible with
// API8.
mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
-
-// TODO is this a good place?
- mSystemServiceManager.startService(ShortcutService.Lifecycle.class);
}
if (!disableSystemUI) {
@@ -1139,6 +1136,8 @@
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
+ // LauncherAppsService uses ShortcutService.
+ mSystemServiceManager.startService(ShortcutService.Lifecycle.class);
mSystemServiceManager.startService(LauncherAppsService.class);
}
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index 6a255e5..e27f69e 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -819,7 +819,11 @@
// server-to-server packets, e.g. for relays.
if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
!isPacketServerToServer(udpSrcPort, udpDstPort)) {
- return null;
+ // This should almost never happen because we use SO_ATTACH_FILTER on the packet
+ // socket to drop packets that don't have the right source ports. However, it's
+ // possible that a packet arrives between when the socket is bound and when the
+ // filter is set. http://b/26696823 .
+ throw new ParseException("Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
}
}
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png b/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png
new file mode 100644
index 0000000..f700326
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_1024x4096.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_16x64.png b/services/tests/servicestests/res/drawable-nodpi/black_16x64.png
new file mode 100644
index 0000000..315763e
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_16x64.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_32x32.png b/services/tests/servicestests/res/drawable-nodpi/black_32x32.png
new file mode 100644
index 0000000..8958f6b
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_32x32.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png b/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png
new file mode 100644
index 0000000..f675030
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_4096x1024.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png b/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png
new file mode 100644
index 0000000..999d858
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_4096x4096.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_512x512.png b/services/tests/servicestests/res/drawable-nodpi/black_512x512.png
new file mode 100644
index 0000000..40d1c2c
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_512x512.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_64x16.png b/services/tests/servicestests/res/drawable-nodpi/black_64x16.png
new file mode 100644
index 0000000..5883015
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_64x16.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/black_64x64.png b/services/tests/servicestests/res/drawable-nodpi/black_64x64.png
new file mode 100644
index 0000000..71cfafc
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/black_64x64.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/icon1.png b/services/tests/servicestests/res/drawable-nodpi/icon1.png
new file mode 100644
index 0000000..64eb294
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/icon1.png
Binary files differ
diff --git a/services/tests/servicestests/res/drawable-nodpi/icon2.png b/services/tests/servicestests/res/drawable-nodpi/icon2.png
new file mode 100644
index 0000000..75024841
--- /dev/null
+++ b/services/tests/servicestests/res/drawable-nodpi/icon2.png
Binary files differ
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index 2a967e6..c322ab8 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -558,6 +558,39 @@
}
@SmallTest
+ public void testUdpInvalidDstPort() throws Exception {
+ final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ // Ethernet header.
+ "9cd917000000001c2e0000000800" +
+ // IP header.
+ "45a00148000040003d115087d18194fb0a0f7af2" +
+ // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
+ // NOTE: The destination port is a non-DHCP port.
+ "0043aaaa01341268" +
+ // BOOTP header.
+ "02010600d628ba8200000000000000000a0f7af2000000000a0fc818" +
+ // MAC address.
+ "9cd91700000000000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Options.
+ "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
+ "d18180060f0777766d2e6564751c040a0fffffff000000"
+ ).toCharArray(), false));
+
+ try {
+ DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
+ fail("Packet with invalid dst port did not throw ParseException");
+ } catch (ParseException expected) {}
+ }
+
+ @SmallTest
public void testMultipleRouters() throws Exception {
final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
// Ethernet header.
diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
index 055ce76..7f28d44 100644
--- a/services/tests/servicestests/src/com/android/server/DropBoxTest.java
+++ b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
@@ -54,7 +54,7 @@
public void testAddText() throws Exception {
File dir = getEmptyDir("testAddText");
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
long before = System.currentTimeMillis();
Thread.sleep(5);
@@ -90,7 +90,7 @@
public void testAddData() throws Exception {
File dir = getEmptyDir("testAddData");
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
long before = System.currentTimeMillis();
dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
@@ -135,7 +135,7 @@
gz3.close();
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
dropbox.addFile("DropBoxTest", f1, DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED);
@@ -201,7 +201,7 @@
new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
// Until a write, the timestamps are taken at face value
DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
@@ -252,7 +252,7 @@
public void testIsTagEnabled() throws Exception {
File dir = getEmptyDir("testIsTagEnabled");
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
long before = System.currentTimeMillis();
dropbox.addText("DropBoxTest", "TEST-ENABLED");
@@ -285,7 +285,7 @@
public void testGetNextEntry() throws Exception {
File dir = getEmptyDir("testGetNextEntry");
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
long before = System.currentTimeMillis();
dropbox.addText("DropBoxTest.A", "A0");
@@ -347,7 +347,7 @@
final int overhead = 64;
long before = System.currentTimeMillis();
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
@@ -441,7 +441,7 @@
// Write one normal entry and another so big that it is instantly tombstoned
long before = System.currentTimeMillis();
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
dropbox.addText("DropBoxTest", "TEST");
addRandomEntry(dropbox, "DropBoxTest", blockSize * 20);
@@ -472,7 +472,7 @@
File dir = getEmptyDir("testFileCountLimits");
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
dropbox.addText("DropBoxTest", "TEST0");
dropbox.addText("DropBoxTest", "TEST1");
dropbox.addText("DropBoxTest", "TEST2");
@@ -525,7 +525,7 @@
File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
new FileOutputStream(dir).close(); // Create an empty file
DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
- DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+ DropBoxManager dropbox = new DropBoxManager(getContext(), service.getServiceStub());
dropbox.addText("DropBoxTest", "should be ignored");
dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 8c47087..e897e3d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1444,10 +1444,10 @@
// Test 1. Caller doesn't have DO or DA.
try {
- dpm.getWifiMacAddress();
+ dpm.getWifiMacAddress(admin1);
fail();
} catch (SecurityException e) {
- MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+ MoreAsserts.assertContainsRegex("No active admin", e.getMessage());
}
// DO needs to be an DA.
@@ -1456,19 +1456,19 @@
// Test 2. Caller has DA, but not DO.
try {
- dpm.getWifiMacAddress();
+ dpm.getWifiMacAddress(admin1);
fail();
} catch (SecurityException e) {
- MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+ MoreAsserts.assertContainsRegex("does not own the device", e.getMessage());
}
// Test 3. Caller has PO, but not DO.
assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
try {
- dpm.getWifiMacAddress();
+ dpm.getWifiMacAddress(admin1);
fail();
} catch (SecurityException e) {
- MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
+ MoreAsserts.assertContainsRegex("does not own the device", e.getMessage());
}
// Remove PO.
@@ -1478,17 +1478,17 @@
assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
// 4-1. But no WifiInfo.
- assertNull(dpm.getWifiMacAddress());
+ assertNull(dpm.getWifiMacAddress(admin1));
// 4-2. Returns WifiInfo, but with the default MAC.
when(mContext.wifiManager.getConnectionInfo()).thenReturn(new WifiInfo());
- assertNull(dpm.getWifiMacAddress());
+ assertNull(dpm.getWifiMacAddress(admin1));
// 4-3. With a real MAC address.
final WifiInfo wi = new WifiInfo();
wi.setMacAddress("11:22:33:44:55:66");
when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi);
- assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress());
+ assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress(admin1));
}
public void testRebootCanOnlyBeCalledByDeviceOwner() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
index a9b6684..036cc66 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -25,19 +25,28 @@
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.content.pm.ShortcutServiceInternal;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.test.AndroidTestCase;
import android.test.mock.MockContext;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import com.android.frameworks.servicestests.R;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
+import com.android.server.pm.ShortcutService.ConfigConstants;
+import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
+
+import libcore.io.IoUtils;
import org.junit.Assert;
@@ -45,13 +54,16 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Tests for ShortcutService and ShortcutManager.
@@ -61,7 +73,11 @@
-r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest \
-w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+
+ * TODO: Add checks with assertAllNotHaveIcon()
+ * TODO: Cross-user test (do in CTS?)
*/
+@SmallTest
public class ShortcutManagerTest extends AndroidTestCase {
private static final String TAG = "ShortcutManagerTest";
@@ -77,10 +93,19 @@
public String getPackageName() {
return mInjectedClientPackage;
}
+
+ @Override
+ public Resources getResources() {
+ return ShortcutManagerTest.this.getContext().getResources();
+ }
}
/** Context used in the service side */
private final class ServiceContext extends MockContext {
+ @Override
+ public Resources getResources() {
+ return ShortcutManagerTest.this.getContext().getResources();
+ }
}
/** ShortcutService with injection override methods. */
@@ -91,10 +116,20 @@
}
@Override
- void injectLoadConfigurationLocked() {
- setResetIntervalForTest(INTERVAL);
- setMaxDynamicShortcutsForTest(MAX_SHORTCUTS);
- setMaxDailyUpdatesForTest(MAX_DAILY_UPDATES);
+ String injectShortcutManagerConstants() {
+ return ConfigConstants.KEY_RESET_INTERVAL_SEC + "=" + (INTERVAL / 1000) + ","
+ + ConfigConstants.KEY_MAX_SHORTCUTS + "=" + MAX_SHORTCUTS + ","
+ + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=" + MAX_DAILY_UPDATES + ","
+ + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=" + MAX_ICON_DIMENSION + ","
+ + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "="
+ + MAX_ICON_DIMENSION_LOWRAM + ","
+ + ConfigConstants.KEY_ICON_FORMAT + "=PNG,"
+ + ConfigConstants.KEY_ICON_QUALITY + "=100";
+ }
+
+ @Override
+ int injectDipToPixel(int dip) {
+ return dip;
}
@Override
@@ -108,7 +143,7 @@
}
@Override
- int injectGetPackageUid(String packageName) {
+ int injectGetPackageUid(String packageName, int userId) {
Integer uid = mInjectedPackageUidMap.get(packageName);
return uid != null ? uid : -1;
}
@@ -122,6 +157,16 @@
File injectUserDataPath(@UserIdInt int userId) {
return new File(mInjectedFilePathRoot, "user-" + userId);
}
+
+ @Override
+ void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
+ // Can't check
+ }
+
+ @Override
+ boolean injectIsLowRamDevice() {
+ return mInjectdIsLowRamDevice;
+ }
}
/** ShortcutManager with injection override methods. */
@@ -157,6 +202,8 @@
private long mInjectedCurrentTimeLillis;
+ private boolean mInjectdIsLowRamDevice;
+
private int mInjectedCallingUid;
private String mInjectedClientPackage;
@@ -181,10 +228,14 @@
private static final long INTERVAL = 10000;
- private static final int MAX_SHORTCUTS = 5;
+ private static final int MAX_SHORTCUTS = 10;
private static final int MAX_DAILY_UPDATES = 3;
+ private static final int MAX_ICON_DIMENSION = 128;
+
+ private static final int MAX_ICON_DIMENSION_LOWRAM = 32;
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -233,7 +284,8 @@
/** Replace the current calling package */
private void setCaller(String packageName) {
mInjectedClientPackage = packageName;
- mInjectedCallingUid = Preconditions.checkNotNull(mInjectedPackageUidMap.get(packageName));
+ mInjectedCallingUid = Preconditions.checkNotNull(mInjectedPackageUidMap.get(packageName),
+ "Unknown package");
}
private String getCallingPackage() {
@@ -343,6 +395,28 @@
}
/**
+ * Make a shortcut with an ID and icon.
+ */
+ private ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
+ return makeShortcut(
+ id, "Title-" + id, /* activity =*/ null, icon,
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* weight =*/ 0);
+ }
+
+ private ShortcutInfo makePackageShortcut(String packageName, String id) {
+ String origCaller = getCallingPackage();
+
+ setCaller(packageName);
+ ShortcutInfo s = makeShortcut(
+ id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+ makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* weight =*/ 0);
+ setCaller(origCaller); // restore the caller
+
+ return s;
+ }
+
+
+ /**
* Make multiple shortcuts with IDs.
*/
private List<ShortcutInfo> makeShortcuts(String... ids) {
@@ -413,6 +487,7 @@
@NonNull
private List<ShortcutInfo> assertShortcutIds(@NonNull List<ShortcutInfo> actualShortcuts,
String... expectedIds) {
+ assertEquals(expectedIds.length, actualShortcuts.size());
final HashSet<String> expected = new HashSet<>(Arrays.asList(expectedIds));
final HashSet<String> actual = new HashSet<>();
for (ShortcutInfo s : actualShortcuts) {
@@ -461,6 +536,35 @@
}
@NonNull
+ private List<ShortcutInfo> assertAllNotHaveIcon(
+ @NonNull List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertNull("ID " + s.getId(), s.getIcon());
+ }
+ return actualShortcuts;
+ }
+
+ @NonNull
+ private List<ShortcutInfo> assertAllHaveIconResId(
+ @NonNull List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
+ assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
+ }
+ return actualShortcuts;
+ }
+
+ @NonNull
+ private List<ShortcutInfo> assertAllHaveIconFile(
+ @NonNull List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
+ assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
+ }
+ return actualShortcuts;
+ }
+
+ @NonNull
private List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
int shortcutFlags) {
for (ShortcutInfo s : actualShortcuts) {
@@ -470,6 +574,24 @@
}
@NonNull
+ private List<ShortcutInfo> assertAllKeyFieldsOnly(
+ @NonNull List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertTrue("ID " + s.getId(), s.hasKeyFieldsOnly());
+ }
+ return actualShortcuts;
+ }
+
+ @NonNull
+ private List<ShortcutInfo> assertAllNotKeyFieldsOnly(
+ @NonNull List<ShortcutInfo> actualShortcuts) {
+ for (ShortcutInfo s : actualShortcuts) {
+ assertFalse("ID " + s.getId(), s.hasKeyFieldsOnly());
+ }
+ return actualShortcuts;
+ }
+
+ @NonNull
private List<ShortcutInfo> assertAllDynamic(@NonNull List<ShortcutInfo> actualShortcuts) {
return assertAllHaveFlags(actualShortcuts, ShortcutInfo.FLAG_DYNAMIC);
}
@@ -488,6 +610,31 @@
return actualShortcuts;
}
+ private void assertBitmapSize(int expectedWidth, int expectedHeight, @NonNull Bitmap bitmap) {
+ assertEquals("width", expectedWidth, bitmap.getWidth());
+ assertEquals("height", expectedHeight, bitmap.getHeight());
+ }
+
+ private <T> void assertAllUnique(Collection<T> list) {
+ final Set<Object> set = new HashSet<>();
+ for (T item : list) {
+ if (set.contains(item)) {
+ fail("Duplicate item found: " + item + " (in the list: " + list + ")");
+ }
+ set.add(item);
+ }
+ }
+
+ @NonNull
+ private Bitmap pfdToBitmap(@NonNull ParcelFileDescriptor pfd) {
+ Preconditions.checkNotNull(pfd);
+ try {
+ return BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
+ } finally {
+ IoUtils.closeQuietly(pfd);
+ }
+ }
+
/**
* Test for the first launch path, no settings file available.
*/
@@ -549,6 +696,44 @@
// TODO Add various broken cases.
}
+ public void testLoadConfig() {
+ mService.updateConfigurationLocked(
+ ConfigConstants.KEY_RESET_INTERVAL_SEC + "=123,"
+ + ConfigConstants.KEY_MAX_SHORTCUTS + "=4,"
+ + ConfigConstants.KEY_MAX_DAILY_UPDATES + "=5,"
+ + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
+ + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
+ + ConfigConstants.KEY_ICON_FORMAT + "=WEBP,"
+ + ConfigConstants.KEY_ICON_QUALITY + "=75");
+ assertEquals(123000, mService.getResetIntervalForTest());
+ assertEquals(4, mService.getMaxDynamicShortcutsForTest());
+ assertEquals(5, mService.getMaxDailyUpdatesForTest());
+ assertEquals(100, mService.getMaxIconDimensionForTest());
+ assertEquals(CompressFormat.WEBP, mService.getIconPersistFormatForTest());
+ assertEquals(75, mService.getIconPersistQualityForTest());
+
+ mInjectdIsLowRamDevice = true;
+ mService.updateConfigurationLocked(
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
+ + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
+ + ConfigConstants.KEY_ICON_FORMAT + "=JPEG");
+ assertEquals(ShortcutService.DEFAULT_RESET_INTERVAL_SEC * 1000,
+ mService.getResetIntervalForTest());
+
+ assertEquals(ShortcutService.DEFAULT_MAX_SHORTCUTS_PER_APP,
+ mService.getMaxDynamicShortcutsForTest());
+
+ assertEquals(ShortcutService.DEFAULT_MAX_DAILY_UPDATES,
+ mService.getMaxDailyUpdatesForTest());
+
+ assertEquals(50, mService.getMaxIconDimensionForTest());
+
+ assertEquals(CompressFormat.JPEG, mService.getIconPersistFormatForTest());
+
+ assertEquals(ShortcutService.DEFAULT_ICON_PERSIST_QUALITY,
+ mService.getIconPersistQualityForTest());
+ }
+
// === Test for app side APIs ===
/** Test for {@link android.content.pm.ShortcutManager#getMaxDynamicShortcutCount()} */
@@ -594,13 +779,17 @@
final ShortcutInfo si3 = makeShortcut("shortcut3");
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2)));
- assertEquals(2, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut1", "shortcut2");
assertEquals(2, mManager.getRemainingCallCount());
// TODO: Check fields
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
- assertEquals(1, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut1");
assertEquals(1, mManager.getRemainingCallCount());
assertTrue(mManager.setDynamicShortcuts(Arrays.asList()));
@@ -629,16 +818,22 @@
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
assertEquals(2, mManager.getRemainingCallCount());
- assertEquals(1, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut1");
assertTrue(mManager.addDynamicShortcut(si2));
assertEquals(1, mManager.getRemainingCallCount());
- assertEquals(2, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut1", "shortcut2");
// Add with the same ID
assertTrue(mManager.addDynamicShortcut(makeShortcut("shortcut1")));
assertEquals(0, mManager.getRemainingCallCount());
- assertEquals(2, mManager.getDynamicShortcuts().size()); // Still 2
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut1", "shortcut2");
// TODO Check max number
@@ -651,24 +846,35 @@
final ShortcutInfo si3 = makeShortcut("shortcut3");
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2, si3)));
- assertEquals(3, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut1", "shortcut2", "shortcut3");
assertEquals(2, mManager.getRemainingCallCount());
mManager.deleteDynamicShortcut("shortcut1");
- assertEquals(2, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut2", "shortcut3");
mManager.deleteDynamicShortcut("shortcut1");
- assertEquals(2, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut2", "shortcut3");
mManager.deleteDynamicShortcut("shortcutXXX");
- assertEquals(2, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut2", "shortcut3");
mManager.deleteDynamicShortcut("shortcut2");
- assertEquals(1, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut3");
mManager.deleteDynamicShortcut("shortcut3");
- assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()));
// Still 2 calls left.
assertEquals(2, mManager.getRemainingCallCount());
@@ -682,7 +888,9 @@
final ShortcutInfo si3 = makeShortcut("shortcut3");
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1, si2, si3)));
- assertEquals(3, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
+ mManager.getDynamicShortcuts()),
+ "shortcut1", "shortcut2", "shortcut3");
assertEquals(2, mManager.getRemainingCallCount());
@@ -732,7 +940,7 @@
// Now it should work.
mInjectedCurrentTimeLillis++;
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1)));
+ assertTrue(mManager.setDynamicShortcuts(Arrays.asList(si1))); // fail
assertEquals(2, mManager.getRemainingCallCount());
mInjectedCurrentTimeLillis++;
@@ -831,6 +1039,226 @@
assertFalse(mManager.setDynamicShortcuts(Arrays.asList(si2)));
}
+ public void testIcons() {
+ final Icon res32x32 = Icon.createWithResource(mContext, R.drawable.black_32x32);
+ final Icon res64x64 = Icon.createWithResource(mContext, R.drawable.black_64x64);
+ final Icon res512x512 = Icon.createWithResource(mContext, R.drawable.black_512x512);
+
+ final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ mContext.getResources(), R.drawable.black_32x32));
+ final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ mContext.getResources(), R.drawable.black_64x64));
+ final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+ mContext.getResources(), R.drawable.black_512x512));
+
+ // Set from package 1
+ setCaller(CALLING_PACKAGE_1);
+ assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ makeShortcutWithIcon("res32x32", res32x32),
+ makeShortcutWithIcon("res64x64", res64x64),
+ makeShortcutWithIcon("bmp32x32", bmp32x32),
+ makeShortcutWithIcon("bmp64x64", bmp64x64),
+ makeShortcutWithIcon("bmp512x512", bmp512x512),
+ makeShortcut("none")
+ )));
+
+ // getDynamicShortcuts() shouldn't return icons, thus assertAllNotHaveIcon().
+ assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
+ "res32x32",
+ "res64x64",
+ "bmp32x32",
+ "bmp64x64",
+ "bmp512x512",
+ "none");
+
+ // Call from another caller with the same ID, just to make sure storage is per-package.
+ setCaller(CALLING_PACKAGE_2);
+ assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ makeShortcutWithIcon("res32x32", res512x512),
+ makeShortcutWithIcon("res64x64", res512x512),
+ makeShortcutWithIcon("none", res512x512)
+ )));
+ assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
+ "res32x32",
+ "res64x64",
+ "none");
+
+ dumpsysOnLogcat();
+
+ // Load from launcher.
+ Bitmap bmp;
+
+ setCaller(LAUNCHER_1);
+
+ // Check hasIconResource()/hasIconFile().
+ assertShortcutIds(assertAllHaveIconResId(mInternal.getShortcutInfo(
+ getCallingPackage(), CALLING_PACKAGE_1, Arrays.asList("res32x32"),
+ getCallingUserId())), "res32x32");
+
+ assertShortcutIds(assertAllHaveIconResId(mInternal.getShortcutInfo(
+ getCallingPackage(), CALLING_PACKAGE_1, Arrays.asList("res64x64"),
+ getCallingUserId())), "res64x64");
+
+ assertShortcutIds(assertAllHaveIconFile(mInternal.getShortcutInfo(
+ getCallingPackage(), CALLING_PACKAGE_1, Arrays.asList("bmp32x32"),
+ getCallingUserId())), "bmp32x32");
+ assertShortcutIds(assertAllHaveIconFile(mInternal.getShortcutInfo(
+ getCallingPackage(), CALLING_PACKAGE_1, Arrays.asList("bmp64x64"),
+ getCallingUserId())), "bmp64x64");
+ assertShortcutIds(assertAllHaveIconFile(mInternal.getShortcutInfo(
+ getCallingPackage(), CALLING_PACKAGE_1, Arrays.asList("bmp512x512"),
+ getCallingUserId())), "bmp512x512");
+
+ // Check
+ assertEquals(
+ R.drawable.black_32x32,
+ mInternal.getShortcutIconResId(getCallingPackage(),
+ makePackageShortcut(CALLING_PACKAGE_1, "res32x32"), getCallingUserId()));
+
+ assertEquals(
+ R.drawable.black_64x64,
+ mInternal.getShortcutIconResId(
+ getCallingPackage(),
+ makePackageShortcut(CALLING_PACKAGE_1, "res64x64"), getCallingUserId()));
+
+ assertEquals(
+ 0, // because it's not a resource
+ mInternal.getShortcutIconResId(
+ getCallingPackage(),
+ makePackageShortcut(CALLING_PACKAGE_1, "bmp32x32"), getCallingUserId()));
+ assertEquals(
+ 0, // because it's not a resource
+ mInternal.getShortcutIconResId(
+ getCallingPackage(),
+ makePackageShortcut(CALLING_PACKAGE_1, "bmp64x64"), getCallingUserId()));
+ assertEquals(
+ 0, // because it's not a resource
+ mInternal.getShortcutIconResId(
+ getCallingPackage(),
+ makePackageShortcut(CALLING_PACKAGE_1, "bmp512x512"), getCallingUserId()));
+
+ bmp = pfdToBitmap(mInternal.getShortcutIconFd(
+ getCallingPackage(),
+ makePackageShortcut(CALLING_PACKAGE_1, "bmp32x32"), getCallingUserId()));
+ assertBitmapSize(32, 32, bmp);
+
+ bmp = pfdToBitmap(mInternal.getShortcutIconFd(
+ getCallingPackage(),
+ makePackageShortcut(CALLING_PACKAGE_1, "bmp64x64"), getCallingUserId()));
+ assertBitmapSize(64, 64, bmp);
+
+ bmp = pfdToBitmap(mInternal.getShortcutIconFd(
+ getCallingPackage(),
+ makePackageShortcut(CALLING_PACKAGE_1, "bmp512x512"), getCallingUserId()));
+ assertBitmapSize(128, 128, bmp);
+
+ // TODO Test the content URI case too.
+ }
+
+ private void checkShrinkBitmap(int expectedWidth, int expectedHeight, int resId, int maxSize) {
+ assertBitmapSize(expectedWidth, expectedHeight,
+ ShortcutService.shrinkBitmap(BitmapFactory.decodeResource(
+ mContext.getResources(), resId),
+ maxSize));
+ }
+
+ public void testShrinkBitmap() {
+ checkShrinkBitmap(32, 32, R.drawable.black_512x512, 32);
+ checkShrinkBitmap(511, 511, R.drawable.black_512x512, 511);
+ checkShrinkBitmap(512, 512, R.drawable.black_512x512, 512);
+
+ checkShrinkBitmap(1024, 4096, R.drawable.black_1024x4096, 4096);
+ checkShrinkBitmap(1024, 4096, R.drawable.black_1024x4096, 4100);
+ checkShrinkBitmap(512, 2048, R.drawable.black_1024x4096, 2048);
+
+ checkShrinkBitmap(4096, 1024, R.drawable.black_4096x1024, 4096);
+ checkShrinkBitmap(4096, 1024, R.drawable.black_4096x1024, 4100);
+ checkShrinkBitmap(2048, 512, R.drawable.black_4096x1024, 2048);
+ }
+
+ private File openIconFileForWriteAndGetPath(int userId, String packageName)
+ throws IOException {
+ // Shortcut IDs aren't used in the path, so just pass the same ID.
+ final FileOutputStreamWithPath out =
+ mService.openIconFileForWrite(userId, makePackageShortcut(packageName, "id"));
+ out.close();
+ return out.getFile();
+ }
+
+ public void testOpenIconFileForWrite() throws IOException {
+ mInjectedCurrentTimeLillis = 1000;
+
+ final File p10_1_1 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+ final File p10_1_2 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+
+ final File p10_2_1 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
+ final File p10_2_2 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
+
+ final File p11_1_1 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
+ final File p11_1_2 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
+
+ mInjectedCurrentTimeLillis++;
+
+ final File p10_1_3 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+ final File p10_1_4 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+ final File p10_1_5 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+
+ final File p10_2_3 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
+ final File p11_1_3 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
+
+ // Make sure their paths are all unique
+ assertAllUnique(Arrays.asList(
+ p10_1_1,
+ p10_1_2,
+ p10_1_3,
+ p10_1_4,
+ p10_1_5,
+
+ p10_2_1,
+ p10_2_2,
+ p10_2_3,
+
+ p11_1_1,
+ p11_1_2,
+ p11_1_3
+ ));
+
+ // Check each set has the same parent.
+ assertEquals(p10_1_1.getParent(), p10_1_2.getParent());
+ assertEquals(p10_1_1.getParent(), p10_1_3.getParent());
+ assertEquals(p10_1_1.getParent(), p10_1_4.getParent());
+ assertEquals(p10_1_1.getParent(), p10_1_5.getParent());
+
+ assertEquals(p10_2_1.getParent(), p10_2_2.getParent());
+ assertEquals(p10_2_1.getParent(), p10_2_3.getParent());
+
+ assertEquals(p11_1_1.getParent(), p11_1_2.getParent());
+ assertEquals(p11_1_1.getParent(), p11_1_3.getParent());
+
+ // Check the parents are still unique.
+ assertAllUnique(Arrays.asList(
+ p10_1_1.getParent(),
+ p10_2_1.getParent(),
+ p11_1_1.getParent()
+ ));
+
+ // All files created at the same time for the same package/user, expcet for the first ones,
+ // will have "_" in the path.
+ assertFalse(p10_1_1.getName().contains("_"));
+ assertTrue(p10_1_2.getName().contains("_"));
+ assertFalse(p10_1_3.getName().contains("_"));
+ assertTrue(p10_1_4.getName().contains("_"));
+ assertTrue(p10_1_5.getName().contains("_"));
+
+ assertFalse(p10_2_1.getName().contains("_"));
+ assertTrue(p10_2_2.getName().contains("_"));
+ assertFalse(p10_2_3.getName().contains("_"));
+
+ assertFalse(p11_1_1.getName().contains("_"));
+ assertTrue(p11_1_2.getName().contains("_"));
+ assertFalse(p11_1_3.getName().contains("_"));
+ }
+
// TODO: updateShortcuts()
// TODO: getPinnedShortcuts()
@@ -860,9 +1288,10 @@
// Get dynamic
assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+ assertAllNotKeyFieldsOnly(
mInternal.getShortcuts(getCallingPackage(), /* time =*/ 0, CALLING_PACKAGE_1,
/* activity =*/ null,
- ShortcutQuery.FLAG_GET_DYNAMIC, getCallingUserId()),
+ ShortcutQuery.FLAG_GET_DYNAMIC, getCallingUserId())),
"s1", "s2"))));
// Get pinned
@@ -874,18 +1303,20 @@
// Get both, with timestamp
assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
- mInternal.getShortcuts(getCallingPackage(), /* time =*/ 1000, CALLING_PACKAGE_2,
+ assertAllNotKeyFieldsOnly(mInternal.getShortcuts(getCallingPackage(),
+ /* time =*/ 1000, CALLING_PACKAGE_2,
/* activity =*/ null,
ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC,
- getCallingUserId()),
+ getCallingUserId())),
"s2", "s3"))));
// FLAG_GET_KEY_FIELDS_ONLY
assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
- mInternal.getShortcuts(getCallingPackage(), /* time =*/ 1000, CALLING_PACKAGE_2,
+ assertAllKeyFieldsOnly(mInternal.getShortcuts(getCallingPackage(),
+ /* time =*/ 1000, CALLING_PACKAGE_2,
/* activity =*/ null,
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY,
- getCallingUserId()),
+ getCallingUserId())),
"s2", "s3"))));
// Pin some shortcuts.
@@ -894,19 +1325,20 @@
// Pinned ones only
assertAllPinned(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
- mInternal.getShortcuts(getCallingPackage(), /* time =*/ 1000, CALLING_PACKAGE_2,
+ assertAllNotKeyFieldsOnly(mInternal.getShortcuts(getCallingPackage(),
+ /* time =*/ 1000, CALLING_PACKAGE_2,
/* activity =*/ null,
ShortcutQuery.FLAG_GET_PINNED,
- getCallingUserId()),
+ getCallingUserId())),
"s3"))));
// All packages.
- assertShortcutIds(
+ assertShortcutIds(assertAllNotKeyFieldsOnly(
mInternal.getShortcuts(getCallingPackage(),
/* time =*/ 5000, /* package= */ null,
/* activity =*/ null,
ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED,
- getCallingUserId()),
+ getCallingUserId())),
"s1", "s3");
// TODO More tests: pinned but dynamic, filter by activity
@@ -968,8 +1400,9 @@
// Note we don't guarantee the orders.
list = assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
+ assertAllNotKeyFieldsOnly(
mInternal.getShortcutInfo(getCallingPackage(), CALLING_PACKAGE_1,
- Arrays.asList("s2", "s1", "s3", null), getCallingUserId()))),
+ Arrays.asList("s2", "s1", "s3", null), getCallingUserId())))),
"s1", "s2");
assertEquals("Title 1", findById(list, "s1").getTitle());
assertEquals("Title 2", findById(list, "s2").getTitle());
@@ -1036,19 +1469,19 @@
setCaller(LAUNCHER_1);
// CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
- assertShortcutIds(assertAllPinned(
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
mInternal.getShortcuts(getCallingPackage(), /* time =*/ 0, CALLING_PACKAGE_1,
- /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED, getCallingUserId())),
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED, getCallingUserId()))),
"s2");
- assertShortcutIds(assertAllPinned(
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
mInternal.getShortcuts(getCallingPackage(), /* time =*/ 0, CALLING_PACKAGE_2,
- /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED, getCallingUserId())),
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED, getCallingUserId()))),
"s3", "s4");
- assertShortcutIds(assertAllPinned(
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
mInternal.getShortcuts(getCallingPackage(), /* time =*/ 0, CALLING_PACKAGE_3,
- /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED, getCallingUserId()))
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED, getCallingUserId())))
/* none */);
}
@@ -1101,15 +1534,15 @@
setCaller(LAUNCHER_1);
Intent intent;
intent = mInternal.createShortcutIntent(getCallingPackage(),
- s1_1.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO), getCallingUserId());
+ CALLING_PACKAGE_1, "s1", getCallingUserId());
assertEquals(ShortcutActivity2.class.getName(), intent.getComponent().getClassName());
intent = mInternal.createShortcutIntent(getCallingPackage(),
- s1_2.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO), getCallingUserId());
+ CALLING_PACKAGE_1, "s2", getCallingUserId());
assertEquals(ShortcutActivity3.class.getName(), intent.getComponent().getClassName());
intent = mInternal.createShortcutIntent(getCallingPackage(),
- s2_1.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO), getCallingUserId());
+ CALLING_PACKAGE_2, "s1", getCallingUserId());
assertEquals(ShortcutActivity.class.getName(), intent.getComponent().getClassName());
// TODO Check extra, etc
diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
index 17039bb..101e200 100644
--- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java
+++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
@@ -101,8 +102,8 @@
TAG, device.getDeviceId(), notification);
}
- void hideNotification(UsbDevice device) {
- mContext.getSystemService(NotificationManager.class).cancel(TAG, device.getDeviceId());
+ void hideNotification(int deviceId) {
+ mContext.getSystemService(NotificationManager.class).cancel(TAG, deviceId);
}
private class Receiver extends BroadcastReceiver {
@@ -121,7 +122,13 @@
}
}
- static boolean isMtpDevice(UsbDevice device) {
+ static boolean shouldShowNotification(PackageManager packageManager, UsbDevice device) {
+ // We don't show MTP notification for devices that has FEATURE_AUTOMOTIVE.
+ return !packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) &&
+ isMtpDevice(device);
+ }
+
+ private static boolean isMtpDevice(UsbDevice device) {
for (int i = 0; i < device.getInterfaceCount(); i++) {
final UsbInterface usbInterface = device.getInterface(i);
if ((usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE &&
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index c4d7336..de9ede3 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -738,7 +738,7 @@
// Send broadcast to running activity with registered intent
mUserContext.sendBroadcast(intent);
- if (MtpNotificationManager.isMtpDevice(device)) {
+ if (MtpNotificationManager.shouldShowNotification(mPackageManager, device)) {
// Show notification if the device is MTP storage.
mMtpNotificationManager.showNotification(device);
} else {
@@ -769,9 +769,7 @@
if (DEBUG) Slog.d(TAG, "usbDeviceRemoved, sending " + intent);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- if (MtpNotificationManager.isMtpDevice(device)) {
- mMtpNotificationManager.hideNotification(device);
- }
+ mMtpNotificationManager.hideNotification(device.getDeviceId());
}
public void accessoryAttached(UsbAccessory accessory) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index e05f00d..40687b0 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -171,7 +171,7 @@
// Fetch a ModelData instance from the hash map. Creates a new one if none
// exists.
- ModelData modelData = getOrCreateGenericModelData(modelId);
+ ModelData modelData = getOrCreateGenericModelDataLocked(modelId);
IRecognitionStatusCallback oldCallback = modelData.getCallback();
if (oldCallback != null) {
@@ -373,7 +373,7 @@
// Also clear the internal state once the recognition has been stopped.
modelData.setLoaded();
modelData.clearCallback();
- if (!computeRecognitionRunning()) {
+ if (!computeRecognitionRunningLocked()) {
internalClearGlobalStateLocked();
}
return status;
@@ -505,12 +505,12 @@
if (modelId == null || mModule == null) {
return STATUS_ERROR;
}
- ModelData modelData = mGenericModelDataMap.get(modelId);
- if (modelData == null) {
- Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" + modelId);
- return STATUS_ERROR;
- }
synchronized (mLock) {
+ ModelData modelData = mGenericModelDataMap.get(modelId);
+ if (modelData == null) {
+ Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" + modelId);
+ return STATUS_ERROR;
+ }
if (!modelData.isModelLoaded()) {
// Nothing to do here.
Slog.i(TAG, "Unload: Given generic model is not loaded:" + modelId);
@@ -530,7 +530,7 @@
Slog.w(TAG, "unloadGenericSoundModel() force-marking model as unloaded.");
}
mGenericModelDataMap.remove(modelId);
- if (DBG) dumpGenericModelState();
+ if (DBG) dumpGenericModelStateLocked();
return status;
}
}
@@ -580,7 +580,7 @@
if (event.status != SoundTrigger.RECOGNITION_STATUS_SUCCESS) {
return;
}
- ModelData model = getModelDataFor(event.soundModelHandle);
+ ModelData model = getModelDataForLocked(event.soundModelHandle);
if (model == null) {
Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " +
event.soundModelHandle);
@@ -919,7 +919,7 @@
mIsPowerSaveMode = mPowerManager.isPowerSaveMode();
}
- private ModelData getOrCreateGenericModelData(UUID modelId) {
+ private ModelData getOrCreateGenericModelDataLocked(UUID modelId) {
ModelData modelData = mGenericModelDataMap.get(modelId);
if (modelData == null) {
modelData = new ModelData(modelId);
@@ -932,7 +932,7 @@
// Instead of maintaining a second hashmap of modelHandle -> ModelData, we just
// iterate through to find the right object (since we don't expect 100s of models
// to be stored).
- private ModelData getModelDataFor(int modelHandle) {
+ private ModelData getModelDataForLocked(int modelHandle) {
// Fetch ModelData object corresponding to the model handle.
for (ModelData model : mGenericModelDataMap.values()) {
if (model.getHandle() == modelHandle) {
@@ -988,7 +988,7 @@
}
}
}
- if (DBG) dumpGenericModelState();
+ if (DBG) dumpGenericModelStateLocked();
return status;
}
@@ -1017,11 +1017,11 @@
}
}
}
- if (DBG) dumpGenericModelState();
+ if (DBG) dumpGenericModelStateLocked();
return status;
}
- private void dumpGenericModelState() {
+ private void dumpGenericModelStateLocked() {
for (UUID modelId : mGenericModelDataMap.keySet()) {
ModelData modelData = mGenericModelDataMap.get(modelId);
Slog.i(TAG, "Model :" + modelData.toString());
@@ -1030,28 +1030,24 @@
// Computes whether we have any recognition running at all (voice or generic). Sets
// the mRecognitionRunning variable with the result.
- private boolean computeRecognitionRunning() {
- synchronized (mLock) {
- if (mModuleProperties == null || mModule == null) {
- mRecognitionRunning = false;
- return mRecognitionRunning;
- }
- if (mKeyphraseListener != null &&
- mKeyphraseStarted &&
- mCurrentKeyphraseModelHandle != INVALID_VALUE &&
- mCurrentSoundModel != null) {
+ private boolean computeRecognitionRunningLocked() {
+ if (mModuleProperties == null || mModule == null) {
+ mRecognitionRunning = false;
+ return mRecognitionRunning;
+ }
+ if (mKeyphraseListener != null && mKeyphraseStarted &&
+ mCurrentKeyphraseModelHandle != INVALID_VALUE && mCurrentSoundModel != null) {
+ mRecognitionRunning = true;
+ return mRecognitionRunning;
+ }
+ for (UUID modelId : mGenericModelDataMap.keySet()) {
+ ModelData modelData = mGenericModelDataMap.get(modelId);
+ if (modelData.isModelStarted()) {
mRecognitionRunning = true;
return mRecognitionRunning;
}
- for (UUID modelId : mGenericModelDataMap.keySet()) {
- ModelData modelData = mGenericModelDataMap.get(modelId);
- if (modelData.isModelStarted()) {
- mRecognitionRunning = true;
- return mRecognitionRunning;
- }
- }
- mRecognitionRunning = false;
}
+ mRecognitionRunning = false;
return mRecognitionRunning;
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index cd1c5e9..ea437d0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -251,6 +251,30 @@
*/
public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
+ /**
+ * Default WFC_IMS_mode 0: WIFI_ONLY
+ * 1: CELLULAR_PREFERRED
+ * 2: WIFI_PREFERRED
+ * @hide
+ */
+ public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT =
+ "carrier_default_wfc_ims_mode_int";
+ /**
+ * Default WFC_IMS_enabled: true VoWiFi by default is on
+ * false VoWiFi by default is off
+ * @hide
+ */
+ public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL =
+ "carrier_default_wfc_ims_enabled_bool";
+
+ /**
+ * Default WFC_IMS_roaming_enabled: true VoWiFi roaming by default is on
+ * false VoWiFi roaming by default is off
+ * @hide
+ */
+ public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL =
+ "carrier_default_wfc_ims_roaming_enabled_bool";
+
/** Flag specifying whether provisioning is required for VOLTE. */
public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
= "carrier_volte_provisioning_required_bool";
@@ -613,6 +637,9 @@
sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
+ sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
+ sDefaults.putInt(KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT, 2);
sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 4bed941..ed7351f8 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -160,7 +160,7 @@
for (String pair : appNames) {
String[] parts = pair.split("\\^");
if (parts.length != 2) {
- Log.e(TAG, "The apps key is incorectly formatted");
+ Log.e(TAG, "The apps key is incorrectly formatted");
fail();
}
@@ -176,6 +176,10 @@
}
}
+ private boolean hasLeanback(Context context) {
+ return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
private void createMappings() {
mNameToIntent = new LinkedHashMap<String, Intent>();
mNameToProcess = new LinkedHashMap<String, String>();
@@ -183,9 +187,12 @@
PackageManager pm = getInstrumentation().getContext()
.getPackageManager();
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
- intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+ intentToResolve.addCategory(hasLeanback(getInstrumentation().getContext()) ?
+ Intent.CATEGORY_LEANBACK_LAUNCHER :
+ Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
resolveLoop(ris, intentToResolve, pm);
+ // For Wear
intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
ris = pm.queryIntentActivities(intentToResolve, 0);
resolveLoop(ris, intentToResolve, pm);
@@ -232,7 +239,7 @@
// report error if any of the following is true:
// * launch thread is alive
// * result is not null, but:
- // * result is not START_SUCESS
+ // * result is not START_SUCCESS
// * or in case of no force stop, result is not TASK_TO_FRONT either
if (t.isAlive() || (result != null
&& ((result.result != ActivityManager.START_SUCCESS)
diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource.xml
new file mode 100644
index 0000000..8093b9d
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+ <base-config>
+ <trust-anchors>
+ </trust-anchors>
+ </base-config>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource_debug.xml b/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource_debug.xml
new file mode 100644
index 0000000..fc24df5
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/bad_extra_debug_resource_debug.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- debug-overrides not inside network-security-config should cause a parsing error -->
+<debug-overrides>
+ <trust-anchors>
+ <certificates src="system" />
+ </trust-anchors>
+</debug-overrides>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource.xml b/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource.xml
new file mode 100644
index 0000000..8093b9d
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+ <base-config>
+ <trust-anchors>
+ </trust-anchors>
+ </base-config>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource_debug.xml b/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource_debug.xml
new file mode 100644
index 0000000..6a2ad37
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/extra_debug_resource_debug.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+ <debug-overrides>
+ <trust-anchors>
+ <certificates src="system" />
+ </trust-anchors>
+ </debug-overrides>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
index 35e3ef4..10bcc18 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
@@ -431,4 +431,37 @@
TestUtils.assertConnectionSucceeds(context, "android.com", 443);
TestUtils.assertUrlConnectionSucceeds(context, "android.com", 443);
}
+
+ public void testExtraDebugResource() throws Exception {
+ XmlConfigSource source =
+ new XmlConfigSource(getContext(), R.xml.extra_debug_resource, true);
+ ApplicationConfig appConfig = new ApplicationConfig(source);
+ assertFalse(appConfig.hasPerDomainConfigs());
+ NetworkSecurityConfig config = appConfig.getConfigForHostname("");
+ MoreAsserts.assertNotEmpty(config.getTrustAnchors());
+
+ // Check that the _debug file is ignored if debug is false.
+ source = new XmlConfigSource(getContext(), R.xml.extra_debug_resource, false);
+ appConfig = new ApplicationConfig(source);
+ assertFalse(appConfig.hasPerDomainConfigs());
+ config = appConfig.getConfigForHostname("");
+ MoreAsserts.assertEmpty(config.getTrustAnchors());
+ }
+
+ public void testExtraDebugResourceIgnored() throws Exception {
+ // Verify that parsing the extra debug config resource fails only when debugging is true.
+ XmlConfigSource source =
+ new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource, false);
+ ApplicationConfig appConfig = new ApplicationConfig(source);
+ // Force parsing the config file.
+ appConfig.getConfigForHostname("");
+
+ source = new XmlConfigSource(getContext(), R.xml.bad_extra_debug_resource, true);
+ appConfig = new ApplicationConfig(source);
+ try {
+ appConfig.getConfigForHostname("");
+ fail("Bad extra debug resource did not fail to parse");
+ } catch (RuntimeException expected) {
+ }
+ }
}
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 57a7692..d311b3d 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -90,6 +90,7 @@
proto/TableProtoSerializer_test.cpp \
split/TableSplitter_test.cpp \
util/BigBuffer_test.cpp \
+ util/Files_test.cpp \
util/Maybe_test.cpp \
util/StringPiece_test.cpp \
util/Util_test.cpp \
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 4d1db5b..03ca42b 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -77,7 +77,7 @@
ResourceType type;
std::u16string entry;
- ResourceName() = default;
+ ResourceName() : type(ResourceType::kRaw) {}
ResourceName(const StringPiece16& p, ResourceType t, const StringPiece16& e);
bool isValid() const;
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 5003d96..418a802 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -729,12 +729,18 @@
std::string outPath = mOptions.generateJavaClassPath.value();
file::appendPath(&outPath, file::packageToPath(util::utf16ToUtf8(outPackage)));
- file::mkdirs(outPath);
+ if (!file::mkdirs(outPath)) {
+ mContext->getDiagnostics()->error(
+ DiagMessage() << "failed to create directory '" << outPath << "'");
+ return false;
+ }
+
file::appendPath(&outPath, "R.java");
std::ofstream fout(outPath, std::ofstream::binary);
if (!fout) {
- mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(
+ DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
return false;
}
@@ -743,6 +749,11 @@
mContext->getDiagnostics()->error(DiagMessage(outPath) << generator.getError());
return false;
}
+
+ if (!fout) {
+ mContext->getDiagnostics()->error(
+ DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
+ }
return true;
}
@@ -754,12 +765,18 @@
std::string outPath = mOptions.generateJavaClassPath.value();
file::appendPath(&outPath,
file::packageToPath(util::utf16ToUtf8(mContext->getCompilationPackage())));
- file::mkdirs(outPath);
+ if (!file::mkdirs(outPath)) {
+ mContext->getDiagnostics()->error(
+ DiagMessage() << "failed to create directory '" << outPath << "'");
+ return false;
+ }
+
file::appendPath(&outPath, "Manifest.java");
std::ofstream fout(outPath, std::ofstream::binary);
if (!fout) {
- mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(
+ DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
return false;
}
@@ -770,7 +787,8 @@
}
if (!fout) {
- mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(
+ DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
return false;
}
return true;
@@ -781,15 +799,18 @@
return true;
}
- std::ofstream fout(mOptions.generateProguardRulesPath.value(), std::ofstream::binary);
+ const std::string& outPath = mOptions.generateProguardRulesPath.value();
+ std::ofstream fout(outPath, std::ofstream::binary);
if (!fout) {
- mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(
+ DiagMessage() << "failed to open '" << outPath << "': " << strerror(errno));
return false;
}
proguard::writeKeepSet(&fout, keepSet);
if (!fout) {
- mContext->getDiagnostics()->error(DiagMessage() << strerror(errno));
+ mContext->getDiagnostics()->error(
+ DiagMessage() << "failed writing to '" << outPath << "': " << strerror(errno));
return false;
}
return true;
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 04e8199..6428e98 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -96,7 +96,7 @@
const char* start = path.begin();
const char* end = path.end();
for (const char* current = start; current != end; ++current) {
- if (*current == sDirSep) {
+ if (*current == sDirSep && current != start) {
StringPiece parentPath(start, current - start);
int result = mkdirImpl(parentPath);
if (result < 0 && errno != EEXIST) {
@@ -139,6 +139,20 @@
return {};
}
+void appendPath(std::string* base, StringPiece part) {
+ assert(base);
+ const bool baseHasTrailingSep = (!base->empty() && *(base->end() - 1) == sDirSep);
+ const bool partHasLeadingSep = (!part.empty() && *(part.begin()) == sDirSep);
+ if (baseHasTrailingSep && partHasLeadingSep) {
+ // Remove the part's leading sep
+ part = part.substr(1, part.size() - 1);
+ } else if (!baseHasTrailingSep && !partHasLeadingSep) {
+ // None of the pieces has a separator.
+ *base += sDirSep;
+ }
+ base->append(part.data(), part.size());
+}
+
std::string packageToPath(const StringPiece& package) {
std::string outPath;
for (StringPiece part : util::tokenize<char>(package, '.')) {
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index c58ba5d..c2e6115 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -61,14 +61,7 @@
/*
* Appends a path to `base`, separated by the directory separator.
*/
-void appendPath(std::string* base, const StringPiece& part);
-
-/*
- * Appends a series of paths to `base`, separated by the
- * system directory separator.
- */
-template <typename... Ts >
-void appendPath(std::string* base, const StringPiece& part, const Ts&... parts);
+void appendPath(std::string* base, StringPiece part);
/*
* Makes all the directories in `path`. The last element in the path
@@ -139,20 +132,6 @@
std::vector<std::string> mPatternTokens;
};
-inline void appendPath(std::string* base, const StringPiece& part) {
- assert(base);
- *base += sDirSep;
- base->append(part.data(), part.size());
-}
-
-template <typename... Ts >
-void appendPath(std::string* base, const StringPiece& part, const Ts&... parts) {
- assert(base);
- *base += sDirSep;
- base->append(part.data(), part.size());
- appendPath(base, parts...);
-}
-
} // namespace file
} // namespace aapt
diff --git a/tools/aapt2/util/Files_test.cpp b/tools/aapt2/util/Files_test.cpp
new file mode 100644
index 0000000..efb0459
--- /dev/null
+++ b/tools/aapt2/util/Files_test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test/Test.h"
+#include "util/Files.h"
+
+#include <sstream>
+
+namespace aapt {
+namespace file {
+
+class FilesTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ std::stringstream builder;
+ builder << "hello" << sDirSep << "there";
+ mExpectedPath = builder.str();
+ }
+
+protected:
+ std::string mExpectedPath;
+};
+
+TEST_F(FilesTest, appendPath) {
+ std::string base = "hello";
+ appendPath(&base, "there");
+ EXPECT_EQ(mExpectedPath, base);
+}
+
+TEST_F(FilesTest, appendPathWithLeadingOrTrailingSeparators) {
+ std::string base = "hello/";
+ appendPath(&base, "there");
+ EXPECT_EQ(mExpectedPath, base);
+
+ base = "hello";
+ appendPath(&base, "/there");
+ EXPECT_EQ(mExpectedPath, base);
+
+ base = "hello/";
+ appendPath(&base, "/there");
+ EXPECT_EQ(mExpectedPath, base);
+}
+
+} // namespace files
+} // namespace aapt