Merge "Add stubs needed to enable javac to compile lambdas" into nyc-dev
diff --git a/Android.mk b/Android.mk
index 46bf460..9183771 100644
--- a/Android.mk
+++ b/Android.mk
@@ -215,6 +215,7 @@
core/java/android/os/IBatteryPropertiesRegistrar.aidl \
core/java/android/os/ICancellationSignal.aidl \
core/java/android/os/IDeviceIdleController.aidl \
+ core/java/android/os/IHardwarePropertiesManager.aidl \
core/java/android/os/IMaintenanceActivityListener.aidl \
core/java/android/os/IMessenger.aidl \
core/java/android/os/INetworkActivityListener.aidl \
diff --git a/api/current.txt b/api/current.txt
index 5d28d2c..abc9e9a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -300,6 +300,7 @@
field public static final int backgroundTint = 16843883; // 0x101046b
field public static final int backgroundTintMode = 16843884; // 0x101046c
field public static final int backupAgent = 16843391; // 0x101027f
+ field public static final int backupInForeground = 16844059; // 0x101051b
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
@@ -4879,7 +4880,6 @@
method public android.graphics.drawable.Icon getLargeIcon();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
- method public android.app.Notification.Topic getTopic();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -4943,7 +4943,6 @@
field public static final int PRIORITY_MAX = 2; // 0x2
field public static final int PRIORITY_MIN = -2; // 0xfffffffe
field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
- field public static final java.lang.String TOPIC_DEFAULT = "system_default_topic";
field public static final int VISIBILITY_PRIVATE = 0; // 0x0
field public static final int VISIBILITY_PUBLIC = 1; // 0x1
field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
@@ -5095,7 +5094,6 @@
method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
- method public android.app.Notification.Builder setTopic(android.app.Notification.Topic);
method public android.app.Notification.Builder setUsesChronometer(boolean);
method public android.app.Notification.Builder setVibrate(long[]);
method public android.app.Notification.Builder setVisibility(int);
@@ -5133,6 +5131,16 @@
method public android.app.PendingIntent getReplyPendingIntent();
}
+ public static class Notification.DecoratedCustomViewStyle extends android.app.Notification.Style {
+ ctor public Notification.DecoratedCustomViewStyle();
+ ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
+ }
+
+ public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
+ ctor public Notification.DecoratedMediaCustomViewStyle();
+ ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
+ }
+
public static abstract interface Notification.Extender {
method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
}
@@ -5163,16 +5171,6 @@
field protected android.app.Notification.Builder mBuilder;
}
- public static class Notification.Topic implements android.os.Parcelable {
- ctor public Notification.Topic(java.lang.String, java.lang.CharSequence);
- method public android.app.Notification.Topic clone();
- method public int describeContents();
- method public java.lang.String getId();
- method public java.lang.CharSequence getLabel();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.Notification.Topic> CREATOR;
- }
-
public static final class Notification.WearableExtender implements android.app.Notification.Extender {
ctor public Notification.WearableExtender();
ctor public Notification.WearableExtender(android.app.Notification);
@@ -5235,7 +5233,7 @@
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
- method public int getImportance(java.lang.String);
+ method public int getImportance();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -5720,6 +5718,7 @@
method public android.graphics.drawable.Drawable getDrawable();
method public android.graphics.drawable.Drawable getFastDrawable();
method public static android.app.WallpaperManager getInstance(android.content.Context);
+ method public android.os.ParcelFileDescriptor getWallpaperFile(int);
method public android.app.WallpaperInfo getWallpaperInfo();
method public boolean hasResourceWallpaper(int);
method public boolean isWallpaperSettingAllowed();
@@ -8006,6 +8005,7 @@
method public final int getColor(int);
method public final android.content.res.ColorStateList getColorStateList(int);
method public abstract android.content.ContentResolver getContentResolver();
+ method public abstract java.io.File getDataDir();
method public abstract java.io.File getDatabasePath(java.lang.String);
method public abstract java.io.File getDir(java.lang.String, int);
method public final android.graphics.drawable.Drawable getDrawable(int);
@@ -8198,6 +8198,7 @@
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -19163,9 +19164,9 @@
method public double getDriftInNsPerSec();
method public double getDriftUncertaintyInNsPerSec();
method public long getFullBiasInNs();
+ method public int getHardwareClockDiscontinuityCount();
method public short getLeapSecond();
method public long getTimeInNs();
- method public long getTimeOfLastHwClockDiscontinuityInNs();
method public double getTimeUncertaintyInNs();
method public byte getType();
method public boolean hasBiasInNs();
@@ -19189,9 +19190,9 @@
method public void setDriftInNsPerSec(double);
method public void setDriftUncertaintyInNsPerSec(double);
method public void setFullBiasInNs(long);
+ method public void setHardwareClockDiscontinuityCount(int);
method public void setLeapSecond(short);
method public void setTimeInNs(long);
- method public void setTimeOfLastHwClockDiscontinuityInNs(long);
method public void setTimeUncertaintyInNs(double);
method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
@@ -19219,6 +19220,7 @@
method public double getCn0InDbHz();
method public double getCodePhaseInChips();
method public double getCodePhaseUncertaintyInChips();
+ method public byte getConstellationType();
method public double getDopplerShiftInHz();
method public double getDopplerShiftUncertaintyInHz();
method public double getElevationInDeg();
@@ -19226,13 +19228,11 @@
method public byte getLossOfLock();
method public byte getMultipathIndicator();
method public double getPseudorangeInMeters();
- method public double getPseudorangeRateCarrierInMetersPerSec();
- method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
method public double getPseudorangeRateInMetersPerSec();
method public double getPseudorangeRateUncertaintyInMetersPerSec();
method public double getPseudorangeUncertaintyInMeters();
- method public long getReceivedGpsTowInNs();
- method public long getReceivedGpsTowUncertaintyInNs();
+ method public long getReceivedSvTimeInNs();
+ method public long getReceivedSvTimeUncertaintyInNs();
method public double getSnrInDb();
method public short getState();
method public short getSvid();
@@ -19289,6 +19289,7 @@
method public void setCn0InDbHz(double);
method public void setCodePhaseInChips(double);
method public void setCodePhaseUncertaintyInChips(double);
+ method public void setConstellationType(byte);
method public void setDopplerShiftInHz(double);
method public void setDopplerShiftUncertaintyInHz(double);
method public void setElevationInDeg(double);
@@ -19296,13 +19297,11 @@
method public void setLossOfLock(byte);
method public void setMultipathIndicator(byte);
method public void setPseudorangeInMeters(double);
- method public void setPseudorangeRateCarrierInMetersPerSec(double);
- method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
method public void setPseudorangeRateInMetersPerSec(double);
method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
method public void setPseudorangeUncertaintyInMeters(double);
- method public void setReceivedGpsTowInNs(long);
- method public void setReceivedGpsTowUncertaintyInNs(long);
+ method public void setReceivedSvTimeInNs(long);
+ method public void setReceivedSvTimeUncertaintyInNs(long);
method public void setSnrInDb(double);
method public void setState(short);
method public void setSvid(short);
@@ -19363,7 +19362,7 @@
method public short getStatus();
method public short getSubmessageId();
method public short getSvid();
- method public byte getType();
+ method public short getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
@@ -19371,14 +19370,19 @@
method public void setStatus(short);
method public void setSubmessageId(short);
method public void setSvid(short);
- method public void setType(byte);
+ method public void setType(short);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
- field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
- field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
- field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
- field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
- field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+ field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
+ field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
+ field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
+ field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
+ field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
+ field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
+ field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
+ field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
+ field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
+ field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
field public static final short STATUS_PARITY_PASSED = 1; // 0x1
field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
field public static final short STATUS_UNKNOWN = 0; // 0x0
@@ -19413,7 +19417,7 @@
public final class GnssStatus {
method public float getAzimuth(int);
- method public int getConstellationType(int);
+ method public byte getConstellationType(int);
method public float getElevation(int);
method public int getNumSatellites();
method public float getSnr(int);
@@ -19421,13 +19425,16 @@
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
- field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
- field public static final int CONSTELLATION_GALILEO = 6; // 0x6
- field public static final int CONSTELLATION_GLONASS = 3; // 0x3
- field public static final int CONSTELLATION_GPS = 1; // 0x1
- field public static final int CONSTELLATION_QZSS = 4; // 0x4
- field public static final int CONSTELLATION_SBAS = 2; // 0x2
- field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final byte CONSTELLATION_GPS = 1; // 0x1
+ field public static final byte CONSTELLATION_QZSS = 4; // 0x4
+ field public static final byte CONSTELLATION_SBAS = 2; // 0x2
+ field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
}
public abstract class GnssStatusCallback {
@@ -20971,6 +20978,7 @@
field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
field public static final java.lang.String KEY_MIME = "mime";
field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
+ field public static final java.lang.String KEY_PCM_ENCODING = "pcm-encoding";
field public static final java.lang.String KEY_PRIORITY = "priority";
field public static final java.lang.String KEY_PROFILE = "profile";
field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
@@ -22545,6 +22553,10 @@
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
method public void playFromUri(android.net.Uri, android.os.Bundle);
+ method public void prepare();
+ method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void prepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void prepareFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -22578,7 +22590,6 @@
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
- field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -22593,6 +22604,10 @@
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+ method public void onPrepare();
+ method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -22649,6 +22664,10 @@
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+ field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+ field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+ field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+ field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
field public static final long ACTION_SET_RATING = 128L; // 0x80L
@@ -22657,7 +22676,6 @@
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
- field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22850,6 +22868,7 @@
public static final class TvContract.Programs.Genres {
method public static java.lang.String[] decode(java.lang.String);
method public static java.lang.String encode(java.lang.String...);
+ method public static boolean isCanonical(java.lang.String);
field public static final java.lang.String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
field public static final java.lang.String ARTS = "ARTS";
field public static final java.lang.String COMEDY = "COMEDY";
@@ -32174,7 +32193,6 @@
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
- field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -34094,6 +34112,7 @@
method public boolean isDigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyGenParameterSpec.Builder {
@@ -34116,6 +34135,7 @@
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -34135,6 +34155,7 @@
method public boolean isInsideSecureHardware();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -34197,6 +34218,7 @@
method public boolean isDigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyProtection.Builder {
@@ -34212,6 +34234,7 @@
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -34582,6 +34605,7 @@
method public final void startActivityAndCollapse(android.content.Intent);
method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
field public static final int TILE_MODE_ACTIVE = 2; // 0x2
field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
@@ -37628,6 +37652,7 @@
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -44341,6 +44366,7 @@
method public int getCursorCapsMode(int);
method public android.text.Editable getEditable();
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -44504,6 +44530,7 @@
method public abstract boolean finishComposingText();
method public abstract int getCursorCapsMode(int);
method public abstract android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public abstract android.os.Handler getHandler();
method public abstract java.lang.CharSequence getSelectedText(int);
method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -44535,6 +44562,7 @@
method public boolean finishComposingText();
method public int getCursorCapsMode(int);
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -53045,7 +53073,7 @@
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
diff --git a/api/system-current.txt b/api/system-current.txt
index a2943ff..b36d7e8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -395,6 +395,7 @@
field public static final int backgroundTint = 16843883; // 0x101046b
field public static final int backgroundTintMode = 16843884; // 0x101046c
field public static final int backupAgent = 16843391; // 0x101027f
+ field public static final int backupInForeground = 16844059; // 0x101051b
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
@@ -5011,7 +5012,6 @@
method public android.graphics.drawable.Icon getLargeIcon();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
- method public android.app.Notification.Topic getTopic();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -5075,7 +5075,6 @@
field public static final int PRIORITY_MAX = 2; // 0x2
field public static final int PRIORITY_MIN = -2; // 0xfffffffe
field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
- field public static final java.lang.String TOPIC_DEFAULT = "system_default_topic";
field public static final int VISIBILITY_PRIVATE = 0; // 0x0
field public static final int VISIBILITY_PUBLIC = 1; // 0x1
field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
@@ -5227,7 +5226,6 @@
method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
- method public android.app.Notification.Builder setTopic(android.app.Notification.Topic);
method public android.app.Notification.Builder setUsesChronometer(boolean);
method public android.app.Notification.Builder setVibrate(long[]);
method public android.app.Notification.Builder setVisibility(int);
@@ -5265,6 +5263,16 @@
method public android.app.PendingIntent getReplyPendingIntent();
}
+ public static class Notification.DecoratedCustomViewStyle extends android.app.Notification.Style {
+ ctor public Notification.DecoratedCustomViewStyle();
+ ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
+ }
+
+ public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
+ ctor public Notification.DecoratedMediaCustomViewStyle();
+ ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
+ }
+
public static abstract interface Notification.Extender {
method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
}
@@ -5295,16 +5303,6 @@
field protected android.app.Notification.Builder mBuilder;
}
- public static class Notification.Topic implements android.os.Parcelable {
- ctor public Notification.Topic(java.lang.String, java.lang.CharSequence);
- method public android.app.Notification.Topic clone();
- method public int describeContents();
- method public java.lang.String getId();
- method public java.lang.CharSequence getLabel();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.Notification.Topic> CREATOR;
- }
-
public static final class Notification.WearableExtender implements android.app.Notification.Extender {
ctor public Notification.WearableExtender();
ctor public Notification.WearableExtender(android.app.Notification);
@@ -5367,7 +5365,7 @@
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
- method public int getImportance(java.lang.String);
+ method public int getImportance();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -5843,6 +5841,7 @@
public class WallpaperManager {
method public void clear() throws java.io.IOException;
method public void clearWallpaper();
+ method public void clearWallpaper(int, int);
method public void clearWallpaperOffsets(android.os.IBinder);
method public void forgetLoadedWallpaper();
method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -5853,6 +5852,7 @@
method public android.graphics.drawable.Drawable getDrawable();
method public android.graphics.drawable.Drawable getFastDrawable();
method public static android.app.WallpaperManager getInstance(android.content.Context);
+ method public android.os.ParcelFileDescriptor getWallpaperFile(int);
method public android.app.WallpaperInfo getWallpaperInfo();
method public boolean hasResourceWallpaper(int);
method public boolean isWallpaperSettingAllowed();
@@ -8297,6 +8297,7 @@
method public final int getColor(int);
method public final android.content.res.ColorStateList getColorStateList(int);
method public abstract android.content.ContentResolver getContentResolver();
+ method public abstract java.io.File getDataDir();
method public abstract java.io.File getDatabasePath(java.lang.String);
method public abstract java.io.File getDir(java.lang.String, int);
method public final android.graphics.drawable.Drawable getDrawable(int);
@@ -8499,6 +8500,7 @@
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -20343,9 +20345,9 @@
method public double getDriftInNsPerSec();
method public double getDriftUncertaintyInNsPerSec();
method public long getFullBiasInNs();
+ method public int getHardwareClockDiscontinuityCount();
method public short getLeapSecond();
method public long getTimeInNs();
- method public long getTimeOfLastHwClockDiscontinuityInNs();
method public double getTimeUncertaintyInNs();
method public byte getType();
method public boolean hasBiasInNs();
@@ -20369,9 +20371,9 @@
method public void setDriftInNsPerSec(double);
method public void setDriftUncertaintyInNsPerSec(double);
method public void setFullBiasInNs(long);
+ method public void setHardwareClockDiscontinuityCount(int);
method public void setLeapSecond(short);
method public void setTimeInNs(long);
- method public void setTimeOfLastHwClockDiscontinuityInNs(long);
method public void setTimeUncertaintyInNs(double);
method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
@@ -20399,6 +20401,7 @@
method public double getCn0InDbHz();
method public double getCodePhaseInChips();
method public double getCodePhaseUncertaintyInChips();
+ method public byte getConstellationType();
method public double getDopplerShiftInHz();
method public double getDopplerShiftUncertaintyInHz();
method public double getElevationInDeg();
@@ -20406,13 +20409,11 @@
method public byte getLossOfLock();
method public byte getMultipathIndicator();
method public double getPseudorangeInMeters();
- method public double getPseudorangeRateCarrierInMetersPerSec();
- method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
method public double getPseudorangeRateInMetersPerSec();
method public double getPseudorangeRateUncertaintyInMetersPerSec();
method public double getPseudorangeUncertaintyInMeters();
- method public long getReceivedGpsTowInNs();
- method public long getReceivedGpsTowUncertaintyInNs();
+ method public long getReceivedSvTimeInNs();
+ method public long getReceivedSvTimeUncertaintyInNs();
method public double getSnrInDb();
method public short getState();
method public short getSvid();
@@ -20469,6 +20470,7 @@
method public void setCn0InDbHz(double);
method public void setCodePhaseInChips(double);
method public void setCodePhaseUncertaintyInChips(double);
+ method public void setConstellationType(byte);
method public void setDopplerShiftInHz(double);
method public void setDopplerShiftUncertaintyInHz(double);
method public void setElevationInDeg(double);
@@ -20476,13 +20478,11 @@
method public void setLossOfLock(byte);
method public void setMultipathIndicator(byte);
method public void setPseudorangeInMeters(double);
- method public void setPseudorangeRateCarrierInMetersPerSec(double);
- method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
method public void setPseudorangeRateInMetersPerSec(double);
method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
method public void setPseudorangeUncertaintyInMeters(double);
- method public void setReceivedGpsTowInNs(long);
- method public void setReceivedGpsTowUncertaintyInNs(long);
+ method public void setReceivedSvTimeInNs(long);
+ method public void setReceivedSvTimeUncertaintyInNs(long);
method public void setSnrInDb(double);
method public void setState(short);
method public void setSvid(short);
@@ -20543,7 +20543,7 @@
method public short getStatus();
method public short getSubmessageId();
method public short getSvid();
- method public byte getType();
+ method public short getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
@@ -20551,14 +20551,19 @@
method public void setStatus(short);
method public void setSubmessageId(short);
method public void setSvid(short);
- method public void setType(byte);
+ method public void setType(short);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
- field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
- field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
- field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
- field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
- field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+ field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
+ field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
+ field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
+ field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
+ field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
+ field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
+ field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
+ field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
+ field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
+ field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
field public static final short STATUS_PARITY_PASSED = 1; // 0x1
field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
field public static final short STATUS_UNKNOWN = 0; // 0x0
@@ -20593,7 +20598,7 @@
public final class GnssStatus {
method public float getAzimuth(int);
- method public int getConstellationType(int);
+ method public byte getConstellationType(int);
method public float getElevation(int);
method public int getNumSatellites();
method public float getSnr(int);
@@ -20601,13 +20606,16 @@
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
- field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
- field public static final int CONSTELLATION_GALILEO = 6; // 0x6
- field public static final int CONSTELLATION_GLONASS = 3; // 0x3
- field public static final int CONSTELLATION_GPS = 1; // 0x1
- field public static final int CONSTELLATION_QZSS = 4; // 0x4
- field public static final int CONSTELLATION_SBAS = 2; // 0x2
- field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final byte CONSTELLATION_GPS = 1; // 0x1
+ field public static final byte CONSTELLATION_QZSS = 4; // 0x4
+ field public static final byte CONSTELLATION_SBAS = 2; // 0x2
+ field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
}
public abstract class GnssStatusCallback {
@@ -22470,6 +22478,7 @@
field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
field public static final java.lang.String KEY_MIME = "mime";
field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
+ field public static final java.lang.String KEY_PCM_ENCODING = "pcm-encoding";
field public static final java.lang.String KEY_PRIORITY = "priority";
field public static final java.lang.String KEY_PROFILE = "profile";
field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
@@ -24117,6 +24126,10 @@
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
method public void playFromUri(android.net.Uri, android.os.Bundle);
+ method public void prepare();
+ method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void prepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void prepareFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -24150,7 +24163,6 @@
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
- field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -24165,6 +24177,10 @@
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+ method public void onPrepare();
+ method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -24221,6 +24237,10 @@
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+ field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+ field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+ field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+ field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
field public static final long ACTION_SET_RATING = 128L; // 0x80L
@@ -24229,7 +24249,6 @@
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
- field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -26398,6 +26417,7 @@
field public int numberBurst;
field public int preamble;
field public int requestType;
+ field public boolean secure;
}
public static class RttManager.RttResult {
@@ -26429,6 +26449,7 @@
field public deprecated long rtt_sd_ns;
field public deprecated long rtt_spread_ns;
field public int rxRate;
+ field public boolean secure;
field public int status;
field public int successMeasurementFrameNumber;
field public long ts;
@@ -34661,7 +34682,6 @@
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
- field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -36583,6 +36603,7 @@
method public boolean isDigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyGenParameterSpec.Builder {
@@ -36605,6 +36626,7 @@
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -36624,6 +36646,7 @@
method public boolean isInsideSecureHardware();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -36686,6 +36709,7 @@
method public boolean isDigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyProtection.Builder {
@@ -36701,6 +36725,7 @@
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -36972,9 +36997,8 @@
field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
- field public static final int REASON_PACKAGE_SUSPENDED = 15; // 0xf
- field public static final int REASON_PROFILE_TURNED_OFF = 16; // 0x10
- field public static final int REASON_TOPIC_BANNED = 14; // 0xe
+ field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
+ field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
field public static final int REASON_USER_STOPPED = 6; // 0x6
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
@@ -37136,6 +37160,7 @@
method public final void startActivityAndCollapse(android.content.Intent);
method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
field public static final int TILE_MODE_ACTIVE = 2; // 0x2
field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
@@ -40376,6 +40401,7 @@
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -47102,6 +47128,7 @@
method public int getCursorCapsMode(int);
method public android.text.Editable getEditable();
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -47265,6 +47292,7 @@
method public abstract boolean finishComposingText();
method public abstract int getCursorCapsMode(int);
method public abstract android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public abstract android.os.Handler getHandler();
method public abstract java.lang.CharSequence getSelectedText(int);
method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -47296,6 +47324,7 @@
method public boolean finishComposingText();
method public int getCursorCapsMode(int);
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -48546,6 +48575,7 @@
method public abstract void onConfigurationChanged(android.content.res.Configuration);
method public abstract android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo);
method public abstract void onDetachedFromWindow();
+ method public abstract boolean onDragEvent(android.view.DragEvent);
method public abstract void onDraw(android.graphics.Canvas);
method public abstract void onDrawVerticalScrollBar(android.graphics.Canvas, android.graphics.drawable.Drawable, int, int, int, int);
method public abstract void onFinishTemporaryDetach();
@@ -56139,7 +56169,7 @@
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
diff --git a/api/test-current.txt b/api/test-current.txt
index d42c18c..3878fbf 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -300,6 +300,7 @@
field public static final int backgroundTint = 16843883; // 0x101046b
field public static final int backgroundTintMode = 16843884; // 0x101046c
field public static final int backupAgent = 16843391; // 0x101027f
+ field public static final int backupInForeground = 16844059; // 0x101051b
field public static final int banner = 16843762; // 0x10103f2
field public static final int baseline = 16843548; // 0x101031c
field public static final int baselineAlignBottom = 16843042; // 0x1010122
@@ -4879,7 +4880,6 @@
method public android.graphics.drawable.Icon getLargeIcon();
method public android.graphics.drawable.Icon getSmallIcon();
method public java.lang.String getSortKey();
- method public android.app.Notification.Topic getTopic();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -4943,7 +4943,6 @@
field public static final int PRIORITY_MAX = 2; // 0x2
field public static final int PRIORITY_MIN = -2; // 0xfffffffe
field public static final deprecated int STREAM_DEFAULT = -1; // 0xffffffff
- field public static final java.lang.String TOPIC_DEFAULT = "system_default_topic";
field public static final int VISIBILITY_PRIVATE = 0; // 0x0
field public static final int VISIBILITY_PUBLIC = 1; // 0x1
field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
@@ -5095,7 +5094,6 @@
method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
- method public android.app.Notification.Builder setTopic(android.app.Notification.Topic);
method public android.app.Notification.Builder setUsesChronometer(boolean);
method public android.app.Notification.Builder setVibrate(long[]);
method public android.app.Notification.Builder setVisibility(int);
@@ -5133,6 +5131,16 @@
method public android.app.PendingIntent getReplyPendingIntent();
}
+ public static class Notification.DecoratedCustomViewStyle extends android.app.Notification.Style {
+ ctor public Notification.DecoratedCustomViewStyle();
+ ctor public Notification.DecoratedCustomViewStyle(android.app.Notification.Builder);
+ }
+
+ public static class Notification.DecoratedMediaCustomViewStyle extends android.app.Notification.MediaStyle {
+ ctor public Notification.DecoratedMediaCustomViewStyle();
+ ctor public Notification.DecoratedMediaCustomViewStyle(android.app.Notification.Builder);
+ }
+
public static abstract interface Notification.Extender {
method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
}
@@ -5163,16 +5171,6 @@
field protected android.app.Notification.Builder mBuilder;
}
- public static class Notification.Topic implements android.os.Parcelable {
- ctor public Notification.Topic(java.lang.String, java.lang.CharSequence);
- method public android.app.Notification.Topic clone();
- method public int describeContents();
- method public java.lang.String getId();
- method public java.lang.CharSequence getLabel();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.app.Notification.Topic> CREATOR;
- }
-
public static final class Notification.WearableExtender implements android.app.Notification.Extender {
ctor public Notification.WearableExtender();
ctor public Notification.WearableExtender(android.app.Notification);
@@ -5235,7 +5233,7 @@
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
method public final int getCurrentInterruptionFilter();
- method public int getImportance(java.lang.String);
+ method public int getImportance();
method public android.app.NotificationManager.Policy getNotificationPolicy();
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
@@ -5722,6 +5720,7 @@
method public android.graphics.drawable.Drawable getDrawable();
method public android.graphics.drawable.Drawable getFastDrawable();
method public static android.app.WallpaperManager getInstance(android.content.Context);
+ method public android.os.ParcelFileDescriptor getWallpaperFile(int);
method public android.app.WallpaperInfo getWallpaperInfo();
method public boolean hasResourceWallpaper(int);
method public boolean isWallpaperSettingAllowed();
@@ -8009,6 +8008,7 @@
method public final int getColor(int);
method public final android.content.res.ColorStateList getColorStateList(int);
method public abstract android.content.ContentResolver getContentResolver();
+ method public abstract java.io.File getDataDir();
method public abstract java.io.File getDatabasePath(java.lang.String);
method public abstract java.io.File getDir(java.lang.String, int);
method public final android.graphics.drawable.Drawable getDrawable(int);
@@ -8202,6 +8202,7 @@
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -19171,9 +19172,9 @@
method public double getDriftInNsPerSec();
method public double getDriftUncertaintyInNsPerSec();
method public long getFullBiasInNs();
+ method public int getHardwareClockDiscontinuityCount();
method public short getLeapSecond();
method public long getTimeInNs();
- method public long getTimeOfLastHwClockDiscontinuityInNs();
method public double getTimeUncertaintyInNs();
method public byte getType();
method public boolean hasBiasInNs();
@@ -19197,9 +19198,9 @@
method public void setDriftInNsPerSec(double);
method public void setDriftUncertaintyInNsPerSec(double);
method public void setFullBiasInNs(long);
+ method public void setHardwareClockDiscontinuityCount(int);
method public void setLeapSecond(short);
method public void setTimeInNs(long);
- method public void setTimeOfLastHwClockDiscontinuityInNs(long);
method public void setTimeUncertaintyInNs(double);
method public void setType(byte);
method public void writeToParcel(android.os.Parcel, int);
@@ -19227,6 +19228,7 @@
method public double getCn0InDbHz();
method public double getCodePhaseInChips();
method public double getCodePhaseUncertaintyInChips();
+ method public byte getConstellationType();
method public double getDopplerShiftInHz();
method public double getDopplerShiftUncertaintyInHz();
method public double getElevationInDeg();
@@ -19234,13 +19236,11 @@
method public byte getLossOfLock();
method public byte getMultipathIndicator();
method public double getPseudorangeInMeters();
- method public double getPseudorangeRateCarrierInMetersPerSec();
- method public double getPseudorangeRateCarrierUncertaintyInMetersPerSec();
method public double getPseudorangeRateInMetersPerSec();
method public double getPseudorangeRateUncertaintyInMetersPerSec();
method public double getPseudorangeUncertaintyInMeters();
- method public long getReceivedGpsTowInNs();
- method public long getReceivedGpsTowUncertaintyInNs();
+ method public long getReceivedSvTimeInNs();
+ method public long getReceivedSvTimeUncertaintyInNs();
method public double getSnrInDb();
method public short getState();
method public short getSvid();
@@ -19297,6 +19297,7 @@
method public void setCn0InDbHz(double);
method public void setCodePhaseInChips(double);
method public void setCodePhaseUncertaintyInChips(double);
+ method public void setConstellationType(byte);
method public void setDopplerShiftInHz(double);
method public void setDopplerShiftUncertaintyInHz(double);
method public void setElevationInDeg(double);
@@ -19304,13 +19305,11 @@
method public void setLossOfLock(byte);
method public void setMultipathIndicator(byte);
method public void setPseudorangeInMeters(double);
- method public void setPseudorangeRateCarrierInMetersPerSec(double);
- method public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double);
method public void setPseudorangeRateInMetersPerSec(double);
method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
method public void setPseudorangeUncertaintyInMeters(double);
- method public void setReceivedGpsTowInNs(long);
- method public void setReceivedGpsTowUncertaintyInNs(long);
+ method public void setReceivedSvTimeInNs(long);
+ method public void setReceivedSvTimeUncertaintyInNs(long);
method public void setSnrInDb(double);
method public void setState(short);
method public void setSvid(short);
@@ -19371,7 +19370,7 @@
method public short getStatus();
method public short getSubmessageId();
method public short getSvid();
- method public byte getType();
+ method public short getType();
method public void reset();
method public void set(android.location.GnssNavigationMessage);
method public void setData(byte[]);
@@ -19379,14 +19378,19 @@
method public void setStatus(short);
method public void setSubmessageId(short);
method public void setSvid(short);
- method public void setType(byte);
+ method public void setType(short);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
- field public static final byte MESSAGE_TYPE_CNAV2 = 4; // 0x4
- field public static final byte MESSAGE_TYPE_L1CA = 1; // 0x1
- field public static final byte MESSAGE_TYPE_L2CNAV = 2; // 0x2
- field public static final byte MESSAGE_TYPE_L5CNAV = 3; // 0x3
- field public static final byte MESSAGE_TYPE_UNKNOWN = 0; // 0x0
+ field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
+ field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
+ field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
+ field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
+ field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
+ field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
+ field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
+ field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
+ field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
+ field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
field public static final short STATUS_PARITY_PASSED = 1; // 0x1
field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
field public static final short STATUS_UNKNOWN = 0; // 0x0
@@ -19421,7 +19425,7 @@
public final class GnssStatus {
method public float getAzimuth(int);
- method public int getConstellationType(int);
+ method public byte getConstellationType(int);
method public float getElevation(int);
method public int getNumSatellites();
method public float getSnr(int);
@@ -19429,13 +19433,16 @@
method public boolean hasAlmanac(int);
method public boolean hasEphemeris(int);
method public boolean usedInFix(int);
- field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
- field public static final int CONSTELLATION_GALILEO = 6; // 0x6
- field public static final int CONSTELLATION_GLONASS = 3; // 0x3
- field public static final int CONSTELLATION_GPS = 1; // 0x1
- field public static final int CONSTELLATION_QZSS = 4; // 0x4
- field public static final int CONSTELLATION_SBAS = 2; // 0x2
- field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+ field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
+ field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
+ field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
+ field public static final byte CONSTELLATION_GPS = 1; // 0x1
+ field public static final byte CONSTELLATION_QZSS = 4; // 0x4
+ field public static final byte CONSTELLATION_SBAS = 2; // 0x2
+ field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+ }
+
+ public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
}
public abstract class GnssStatusCallback {
@@ -19541,8 +19548,8 @@
method public void clearTestProviderStatus(java.lang.String);
method public java.util.List<java.lang.String> getAllProviders();
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
+ method public int getGnssYearOfHardware();
method public deprecated android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
- method public int getGpsYearOfHardware();
method public android.location.Location getLastKnownLocation(java.lang.String);
method public android.location.LocationProvider getProvider(java.lang.String);
method public java.util.List<java.lang.String> getProviders(boolean);
@@ -20980,6 +20987,7 @@
field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
field public static final java.lang.String KEY_MIME = "mime";
field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
+ field public static final java.lang.String KEY_PCM_ENCODING = "pcm-encoding";
field public static final java.lang.String KEY_PRIORITY = "priority";
field public static final java.lang.String KEY_PROFILE = "profile";
field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
@@ -22554,6 +22562,10 @@
method public void playFromMediaId(java.lang.String, android.os.Bundle);
method public void playFromSearch(java.lang.String, android.os.Bundle);
method public void playFromUri(android.net.Uri, android.os.Bundle);
+ method public void prepare();
+ method public void prepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void prepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void prepareFromUri(android.net.Uri, android.os.Bundle);
method public void rewind();
method public void seekTo(long);
method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
@@ -22587,7 +22599,6 @@
method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
- field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
}
@@ -22602,6 +22613,10 @@
method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
method public void onPlayFromUri(android.net.Uri, android.os.Bundle);
+ method public void onPrepare();
+ method public void onPrepareFromMediaId(java.lang.String, android.os.Bundle);
+ method public void onPrepareFromSearch(java.lang.String, android.os.Bundle);
+ method public void onPrepareFromUri(android.net.Uri, android.os.Bundle);
method public void onRewind();
method public void onSeekTo(long);
method public void onSetRating(android.media.Rating);
@@ -22658,6 +22673,10 @@
field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+ field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+ field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+ field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+ field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
field public static final long ACTION_REWIND = 8L; // 0x8L
field public static final long ACTION_SEEK_TO = 256L; // 0x100L
field public static final long ACTION_SET_RATING = 128L; // 0x80L
@@ -22666,7 +22685,6 @@
field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
field public static final long ACTION_STOP = 1L; // 0x1L
field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
- field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
field public static final int STATE_BUFFERING = 6; // 0x6
field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22859,6 +22877,7 @@
public static final class TvContract.Programs.Genres {
method public static java.lang.String[] decode(java.lang.String);
method public static java.lang.String encode(java.lang.String...);
+ method public static boolean isCanonical(java.lang.String);
field public static final java.lang.String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
field public static final java.lang.String ARTS = "ARTS";
field public static final java.lang.String COMEDY = "COMEDY";
@@ -32187,7 +32206,6 @@
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
- field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -34109,6 +34127,7 @@
method public boolean isDigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyGenParameterSpec.Builder {
@@ -34131,6 +34150,7 @@
method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -34150,6 +34170,7 @@
method public boolean isInsideSecureHardware();
method public boolean isUserAuthenticationRequired();
method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -34212,6 +34233,7 @@
method public boolean isDigestsSpecified();
method public boolean isRandomizedEncryptionRequired();
method public boolean isUserAuthenticationRequired();
+ method public boolean isUserAuthenticationValidWhileOnBody();
}
public static final class KeyProtection.Builder {
@@ -34227,6 +34249,7 @@
method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+ method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
}
@@ -34597,6 +34620,7 @@
method public final void startActivityAndCollapse(android.content.Intent);
method public final void unlockAndRun(java.lang.Runnable);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final java.lang.String ACTION_QS_TILE_PREFERENCES = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
field public static final int TILE_MODE_ACTIVE = 2; // 0x2
field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
@@ -37643,6 +37667,7 @@
method public java.lang.ClassLoader getClassLoader();
method public java.io.File getCodeCacheDir();
method public android.content.ContentResolver getContentResolver();
+ method public java.io.File getDataDir();
method public java.io.File getDatabasePath(java.lang.String);
method public java.io.File getDir(java.lang.String, int);
method public java.io.File getExternalCacheDir();
@@ -44358,6 +44383,7 @@
method public int getCursorCapsMode(int);
method public android.text.Editable getEditable();
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -44521,6 +44547,7 @@
method public abstract boolean finishComposingText();
method public abstract int getCursorCapsMode(int);
method public abstract android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public abstract android.os.Handler getHandler();
method public abstract java.lang.CharSequence getSelectedText(int);
method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -44552,6 +44579,7 @@
method public boolean finishComposingText();
method public int getCursorCapsMode(int);
method public android.view.inputmethod.ExtractedText getExtractedText(android.view.inputmethod.ExtractedTextRequest, int);
+ method public android.os.Handler getHandler();
method public java.lang.CharSequence getSelectedText(int);
method public java.lang.CharSequence getTextAfterCursor(int, int);
method public java.lang.CharSequence getTextBeforeCursor(int, int);
@@ -53062,7 +53090,7 @@
ctor public ConnectionPendingException();
}
- public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
+ public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel {
ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
method public abstract java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
diff --git a/cmds/hid/jni/Android.mk b/cmds/hid/jni/Android.mk
index 8163a9d..d41d39d 100644
--- a/cmds/hid/jni/Android.mk
+++ b/cmds/hid/jni/Android.mk
@@ -18,6 +18,6 @@
LOCAL_MODULE := libhidcommand_jni
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -Wall
+LOCAL_CFLAGS += -Wall -Wextra -Werror
include $(BUILD_SHARED_LIBRARY)
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 4278e7d..1ea33ce 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -49,7 +49,7 @@
jmethodID onDeviceError;
} gDeviceCallbackClassInfo;
-static int handleLooperEvents(int fd, int events, void* data) {
+static int handleLooperEvents(int /* fd */, int events, void* data) {
Device* d = reinterpret_cast<Device*>(data);
return d->handleEvents(events);
}
@@ -183,7 +183,7 @@
return data;
}
-static jlong openDevice(JNIEnv* env, jclass clazz, jstring rawName, jint id, jint vid, jint pid,
+static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid,
jbyteArray rawDescriptor, jobject queue, jobject callback) {
ScopedUtfChars name(env, rawName);
if (name.c_str() == nullptr) {
@@ -202,7 +202,7 @@
return reinterpret_cast<jlong>(d);
}
-static void sendReport(JNIEnv* env, jclass clazz, jlong ptr,jbyteArray rawReport) {
+static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr,jbyteArray rawReport) {
size_t size;
std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size);
uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
@@ -211,7 +211,7 @@
}
}
-static void closeDevice(JNIEnv* env, jclass clazz, jlong ptr) {
+static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
if (d) {
delete d;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e3adbda..332c739 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4100,7 +4100,7 @@
* }
* </code></pre></p>
*
- * @param permissions The requested permissions.
+ * @param permissions The requested permissions. Must me non-null and not empty.
* @param requestCode Application specific request code to match with a result
* reported to {@link #onRequestPermissionsResult(int, String[], int[])}.
* Should be >= 0.
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 04979ef..bb36a3e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1532,6 +1532,14 @@
return true;
}
+ case SET_LENIENT_BACKGROUND_CHECK_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ boolean enabled = data.readInt() != 0;
+ setLenientBackgroundCheck(enabled);
+ reply.writeNoException();
+ return true;
+ }
+
case ENTER_SAFE_MODE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
enterSafeMode();
@@ -4855,6 +4863,17 @@
data.recycle();
reply.recycle();
}
+ public void setLenientBackgroundCheck(boolean enabled) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(enabled ? 1 : 0);
+ mRemote.transact(SET_LENIENT_BACKGROUND_CHECK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
public void enterSafeMode() throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 04883a9..02b94de 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4774,6 +4774,12 @@
}
}
+ // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp).
+ private static File getPrimaryProfileFile(String packageName) {
+ return new File("/data/misc/profiles/cur/" + UserHandle.myUserId() +
+ "/" + packageName + "/primary.prof");
+ }
+
private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) {
if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
return;
@@ -4793,10 +4799,7 @@
return;
}
- // Add an extension to the file name to better reveal its intended use.
- // Keep in sync with BackgroundDexOptService.
- final String profileExtension = ".prof";
- final File profileFile = new File(cacheDir, loadedApk.mPackageName + profileExtension);
+ final File profileFile = getPrimaryProfileFile(loadedApk.mPackageName);
if (!profileFile.exists()) {
FileDescriptor fd = null;
try {
@@ -4805,7 +4808,7 @@
Os.fchmod(fd, permissions);
Os.fchown(fd, appInfo.uid, appInfo.uid);
} catch (ErrnoException e) {
- Log.w(TAG, "Unable to create jit profile file " + profileFile, e);
+ Log.v(TAG, "Unable to create jit profile file " + profileFile, e);
try {
Os.unlink(profileFile.getAbsolutePath());
} catch (ErrnoException unlinkErr) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index f0453e9..93452fd 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1265,6 +1265,14 @@
}
/** @hide */
+ public void setUserRestriction(int code, boolean restricted, IBinder token) {
+ try {
+ mService.setUserRestriction(code, restricted, token, mContext.getUserId());
+ } catch (RemoteException e) {
+ }
+ }
+
+ /** @hide */
public void setMode(int code, int uid, String packageName, int mode) {
try {
mService.setMode(code, uid, packageName, mode);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5e8d190..8884949 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -460,7 +460,7 @@
private File getPreferencesDir() {
synchronized (mSync) {
if (mPreferencesDir == null) {
- mPreferencesDir = new File(getDataDirFile(), "shared_prefs");
+ mPreferencesDir = new File(getDataDir(), "shared_prefs");
}
return ensurePrivateDirExists(mPreferencesDir);
}
@@ -525,7 +525,7 @@
public File getFilesDir() {
synchronized (mSync) {
if (mFilesDir == null) {
- mFilesDir = new File(getDataDirFile(), "files");
+ mFilesDir = new File(getDataDir(), "files");
}
return ensurePrivateDirExists(mFilesDir);
}
@@ -535,7 +535,7 @@
public File getNoBackupFilesDir() {
synchronized (mSync) {
if (mNoBackupFilesDir == null) {
- mNoBackupFilesDir = new File(getDataDirFile(), "no_backup");
+ mNoBackupFilesDir = new File(getDataDir(), "no_backup");
}
return ensurePrivateDirExists(mNoBackupFilesDir);
}
@@ -587,7 +587,7 @@
public File getCacheDir() {
synchronized (mSync) {
if (mCacheDir == null) {
- mCacheDir = new File(getDataDirFile(), "cache");
+ mCacheDir = new File(getDataDir(), "cache");
}
return ensurePrivateDirExists(mCacheDir);
}
@@ -597,7 +597,7 @@
public File getCodeCacheDir() {
synchronized (mSync) {
if (mCodeCacheDir == null) {
- mCodeCacheDir = new File(getDataDirFile(), "code_cache");
+ mCodeCacheDir = new File(getDataDir(), "code_cache");
}
return ensurePrivateDirExists(mCodeCacheDir);
}
@@ -724,7 +724,7 @@
if ("android".equals(getPackageName())) {
mDatabasesDir = new File("/data/system");
} else {
- mDatabasesDir = new File(getDataDirFile(), "databases");
+ mDatabasesDir = new File(getDataDir(), "databases");
}
}
return ensurePrivateDirExists(mDatabasesDir);
@@ -1920,7 +1920,8 @@
return mDisplayAdjustments;
}
- private File getDataDirFile() {
+ @Override
+ public File getDataDir() {
if (mPackageInfo != null) {
File res = null;
if (isCredentialEncryptedStorage()) {
@@ -1947,7 +1948,7 @@
public File getDir(String name, int mode) {
checkMode(mode);
name = "app_" + name;
- File file = makeFilename(getDataDirFile(), name);
+ File file = makeFilename(getDataDir(), name);
if (!file.exists()) {
file.mkdir();
setFilePermissionsFromMode(file.getPath(), mode,
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 02a898b..aafb3c6 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1033,7 +1033,7 @@
* false if it is not.
*/
public void setUserVisibleHint(boolean isVisibleToUser) {
- if (!mUserVisibleHint && isVisibleToUser && mState < STARTED) {
+ if (!mUserVisibleHint && isVisibleToUser && mState < STARTED && mFragmentManager != null) {
mFragmentManager.performPendingDeferredStart(this);
}
mUserVisibleHint = isVisibleToUser;
@@ -1203,7 +1203,7 @@
* }
* </code></pre></p>
*
- * @param permissions The requested permissions.
+ * @param permissions The requested permissions. Must me non-null and not empty.
* @param requestCode Application specific request code to match with a result
* reported to {@link #onRequestPermissionsResult(int, String[], int[])}.
* Should be >= 0.
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ca86c18..e4d6835 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -307,6 +307,7 @@
public void setAlwaysFinish(boolean enabled) throws RemoteException;
public void setActivityController(IActivityController watcher)
throws RemoteException;
+ public void setLenientBackgroundCheck(boolean enabled) throws RemoteException;
public void enterSafeMode() throws RemoteException;
@@ -978,4 +979,5 @@
int SUPPORTS_LOCAL_VOICE_INTERACTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 365;
int NOTIFY_PINNED_STACK_ANIMATION_ENDED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 366;
int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367;
+ int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368;
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 3c8dfce..8be00aa 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -48,16 +48,13 @@
boolean areNotificationsEnabledForPackage(String pkg, int uid);
boolean areNotificationsEnabled(String pkg);
- ParceledListSlice getTopics(String pkg, int uid);
- void setVisibilityOverride(String pkg, int uid, in Notification.Topic topic, int visibility);
- int getVisibilityOverride(String pkg, int uid, in Notification.Topic topic);
- void setPriority(String pkg, int uid, in Notification.Topic topic, int priority);
- int getPriority(String pkg, int uid, in Notification.Topic topic);
- void setImportance(String pkg, int uid, in Notification.Topic topic, int importance);
- int getImportance(String pkg, int uid, in Notification.Topic topic);
- int getTopicImportance(String pkg, String topicId);
- boolean doesUserUseTopics(String pkg, int uid);
- boolean hasBannedTopics(String pkg, int uid);
+ void setVisibilityOverride(String pkg, int uid, int visibility);
+ int getVisibilityOverride(String pkg, int uid);
+ void setPriority(String pkg, int uid, int priority);
+ int getPriority(String pkg, int uid);
+ void setImportance(String pkg, int uid, int importance);
+ int getImportance(String pkg, int uid);
+ int getPackageImportance(String pkg);
// TODO: Remove this when callers have been migrated to the equivalent
// INotificationListener method.
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 04493cb..1143c6a 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -27,7 +27,7 @@
interface IWallpaperManager {
/**
- * Set the wallpaper.
+ * Set the wallpaper for the current user.
*
* If 'extras' is non-null, on successful return it will contain:
* EXTRA_SET_WALLPAPER_ID : integer ID that the new wallpaper will have
@@ -56,10 +56,10 @@
void setWallpaperComponent(in ComponentName name);
/**
- * Get the system wallpaper.
+ * Get the wallpaper for a given user.
*/
- ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
- out Bundle outParams);
+ ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, int which,
+ out Bundle outParams, int userId);
/**
* If the current system wallpaper is a live wallpaper component, return the
@@ -71,7 +71,7 @@
/**
* Clear the system wallpaper.
*/
- void clearWallpaper(in String callingPackage);
+ void clearWallpaper(in String callingPackage, int which, int userId);
/**
* Return whether the current system wallpaper has the given name.
@@ -118,4 +118,10 @@
* Check whether setting of wallpapers are allowed for the calling user.
*/
boolean isWallpaperSettingAllowed(in String callingPackage);
+
+ /*
+ * Keyguard: register a callback for being notified that lock-state relevant
+ * wallpaper content has changed.
+ */
+ boolean setLockWallpaperCallback(IWallpaperManagerCallback cb);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 35b7c39..402c112 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -263,8 +263,8 @@
* The view that will represent this notification in the notification list (which is pulled
* down from the status bar).
*
- * As of N, this field is not used. The notification view is determined by the inputs to
- * {@link Notification.Builder}; a custom RemoteViews can optionally be
+ * As of N, this field may be null. The notification view is determined by the inputs
+ * to {@link Notification.Builder}; a custom RemoteViews can optionally be
* supplied with {@link Notification.Builder#setCustomContentView(RemoteViews)}.
*/
@Deprecated
@@ -275,7 +275,7 @@
* opportunity to show more detail. The system UI may choose to show this
* instead of the normal content view at its discretion.
*
- * As of N, this field is not used. The expanded notification view is determined by the
+ * As of N, this field may be null. The expanded notification view is determined by the
* inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
* supplied with {@link Notification.Builder#setCustomBigContentView(RemoteViews)}.
*/
@@ -289,7 +289,7 @@
* choose to show this as a heads-up notification, which will pop up so the user can see
* it without leaving their current activity.
*
- * As of N, this field is not used. The heads-up notification view is determined by the
+ * As of N, this field may be null. The heads-up notification view is determined by the
* inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
* supplied with {@link Notification.Builder#setCustomHeadsUpContentView(RemoteViews)}.
*/
@@ -895,6 +895,11 @@
*/
public static final String EXTRA_BUILDER_APPLICATION_INFO = "android.appInfo";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView";
+
private Icon mSmallIcon;
private Icon mLargeIcon;
@@ -1366,98 +1371,6 @@
public Notification publicVersion;
/**
- * Structure to encapsulate a topic that is shown in Notification settings.
- * It must include an id and label.
- */
- public static class Topic implements Parcelable {
- private final String id;
- private final CharSequence label;
-
- public Topic(String id, CharSequence label) {
- this.id = id;
- this.label = safeCharSequence(label);
- }
-
- private Topic(Parcel in) {
- if (in.readInt() != 0) {
- id = in.readString();
- } else {
- id = null;
- }
- label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- }
-
- public String getId() {
- return id;
- }
-
- public CharSequence getLabel() {
- return label;
- }
-
- @Override
- public String toString() {
- return new StringBuilder(Topic.class.getSimpleName()).append('[')
- .append("id=").append(id)
- .append(",label=").append(label)
- .append(']').toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Topic)) return false;
- if (o == this) return true;
- final Topic other = (Topic) o;
- return Objects.equals(other.id, id)
- && Objects.equals(other.label, label);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id, label);
- }
-
- @Override
- public Topic clone() {
- return new Topic(id, label);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- if (id != null) {
- out.writeInt(1);
- out.writeString(id);
- } else {
- out.writeInt(0);
- }
- TextUtils.writeToParcel(label, out, flags);
- }
- public static final Parcelable.Creator<Topic> CREATOR =
- new Parcelable.Creator<Topic>() {
- public Topic createFromParcel(Parcel in) {
- return new Topic(in);
- }
- public Topic[] newArray(int size) {
- return new Topic[size];
- }
- };
- }
-
- @SystemApi
- public static final String TOPIC_DEFAULT = "system_default_topic";
-
- private Topic topic;
-
- public Topic getTopic() {
- return topic;
- }
-
- /**
* Constructs a Notification object with default values.
* You might want to consider using {@link Builder} instead.
*/
@@ -1583,10 +1496,6 @@
}
color = parcel.readInt();
-
- if (parcel.readInt() != 0) {
- topic = Topic.CREATOR.createFromParcel(parcel);
- }
}
@Override
@@ -1687,10 +1596,6 @@
that.color = this.color;
- if (this.topic != null) {
- that.topic = this.topic.clone();
- }
-
if (!heavy) {
that.lightenPayload(); // will clean out extras
}
@@ -1871,13 +1776,6 @@
}
parcel.writeInt(color);
-
- if (topic != null) {
- parcel.writeInt(1);
- topic.writeToParcel(parcel, 0);
- } else {
- parcel.writeInt(0);
- }
}
/**
@@ -2020,10 +1918,6 @@
sb.append(" publicVersion=");
sb.append(publicVersion.toString());
}
- if (topic != null) {
- sb.append("topic=");
- sb.append(topic.toString());
- }
sb.append(")");
return sb.toString();
}
@@ -2129,8 +2023,23 @@
* </pre>
*/
public static class Builder {
+ /**
+ * @hide
+ */
+ public static final String EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT =
+ "android.rebuild.contentViewActionCount";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT
+ = "android.rebuild.bigViewActionCount";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT
+ = "android.rebuild.hudViewActionCount";
+
private static final int MAX_ACTION_BUTTONS = 3;
- private static final float LARGE_TEXT_SCALE = 1.3f;
private Context mContext;
private Notification mN;
@@ -2980,19 +2889,6 @@
return this;
}
- /**
- * Sets the topic of this notification. Topics are typically displayed in Notification
- * settings.
- * <p>
- * Every topic must have an id and a textual label.
- *
- * @param topic The topic to add.
- */
- public Builder setTopic(Topic topic) {
- mN.topic = topic;
- return this;
- }
-
private Drawable getProfileBadgeDrawable() {
// Note: This assumes that the current user can read the profile badge of the
// originating user.
@@ -3338,7 +3234,7 @@
* 3. Standard template view
*/
public RemoteViews makeContentView() {
- if (mN.contentView != null) {
+ if (mN.contentView != null && (mStyle == null || !mStyle.displayCustomViewInline())) {
return mN.contentView;
} else if (mStyle != null) {
final RemoteViews styleView = mStyle.makeContentView();
@@ -3354,7 +3250,8 @@
*/
public RemoteViews makeBigContentView() {
RemoteViews result = null;
- if (mN.bigContentView != null) {
+ if (mN.bigContentView != null
+ && (mStyle == null || !mStyle.displayCustomViewInline())) {
return mN.bigContentView;
} else if (mStyle != null) {
result = mStyle.makeBigContentView();
@@ -3395,7 +3292,8 @@
* Construct a RemoteViews for the final heads-up notification layout.
*/
public RemoteViews makeHeadsUpContentView() {
- if (mN.headsUpContentView != null) {
+ if (mN.headsUpContentView != null
+ && (mStyle == null || !mStyle.displayCustomViewInline())) {
return mN.headsUpContentView;
} else if (mStyle != null) {
final RemoteViews styleView = mStyle.makeHeadsUpContentView();
@@ -3532,6 +3430,10 @@
mN.extras.putStringArray(EXTRA_PEOPLE,
mPersonList.toArray(new String[mPersonList.size()]));
}
+ if (mN.bigContentView != null || mN.contentView != null
+ || mN.headsUpContentView != null) {
+ mN.extras.putBoolean(EXTRA_CONTAINS_CUSTOM_VIEW, true);
+ }
return mN;
}
@@ -3556,8 +3458,9 @@
}
private static Class<? extends Style> getNotificationStyleClass(String templateClass) {
- Class<? extends Style>[] classes = new Class[]{
- BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class};
+ Class<? extends Style>[] classes = new Class[] {
+ BigTextStyle.class, BigPictureStyle.class, InboxStyle.class, MediaStyle.class,
+ DecoratedCustomViewStyle.class, DecoratedMediaCustomViewStyle.class };
for (Class<? extends Style> innerClass : classes) {
if (templateClass.equals(innerClass.getName())) {
return innerClass;
@@ -3566,19 +3469,6 @@
return null;
}
- private void setBuilderContentView(Notification n, RemoteViews contentView) {
- n.contentView = contentView;
- }
-
- private void setBuilderBigContentView(Notification n, RemoteViews bigContentView) {
- n.bigContentView = bigContentView;
- }
-
- private void setBuilderHeadsUpContentView(Notification n,
- RemoteViews headsUpContentView) {
- n.headsUpContentView = headsUpContentView;
- }
-
/**
* @deprecated Use {@link #build()} instead.
*/
@@ -3606,6 +3496,28 @@
mStyle.buildStyled(mN);
}
+ if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+ if (mN.contentView == null) {
+ mN.contentView = makeContentView();
+ mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
+ mN.contentView.getSequenceNumber());
+ }
+ if (mN.bigContentView == null) {
+ mN.bigContentView = makeBigContentView();
+ if (mN.bigContentView != null) {
+ mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
+ mN.bigContentView.getSequenceNumber());
+ }
+ }
+ if (mN.headsUpContentView == null) {
+ mN.headsUpContentView = makeHeadsUpContentView();
+ if (mN.headsUpContentView != null) {
+ mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
+ mN.headsUpContentView.getSequenceNumber());
+ }
+ }
+ }
+
if ((mN.defaults & DEFAULT_LIGHTS) != 0) {
mN.flags |= FLAG_SHOW_LIGHTS;
}
@@ -3623,6 +3535,40 @@
return n;
}
+ /**
+ * @hide
+ */
+ public static void stripForDelivery(Notification n) {
+ String templateClass = n.extras.getString(EXTRA_TEMPLATE);
+ if (TextUtils.isEmpty(templateClass)) {
+ return;
+ }
+ // Only strip views for known Styles because we won't know how to
+ // re-create them otherwise.
+ if (getNotificationStyleClass(templateClass) == null) {
+ return;
+ }
+ // Get rid of unmodified BuilderRemoteViews.
+ if (n.contentView instanceof BuilderRemoteViews &&
+ n.extras.getInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, -1) ==
+ n.contentView.getSequenceNumber()) {
+ n.contentView = null;
+ n.extras.remove(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT);
+ }
+ if (n.bigContentView instanceof BuilderRemoteViews &&
+ n.extras.getInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, -1) ==
+ n.bigContentView.getSequenceNumber()) {
+ n.bigContentView = null;
+ n.extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT);
+ }
+ if (n.headsUpContentView instanceof BuilderRemoteViews &&
+ n.extras.getInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, -1) ==
+ n.headsUpContentView.getSequenceNumber()) {
+ n.headsUpContentView = null;
+ n.extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT);
+ }
+ }
+
private int getBaseLayoutResource() {
return R.layout.notification_template_material_base;
}
@@ -3819,6 +3765,14 @@
public boolean hasSummaryInHeader() {
return true;
}
+
+ /**
+ * @hide
+ * @return Whether custom content views are displayed inline in the style
+ */
+ public boolean displayCustomViewInline() {
+ return false;
+ }
}
/**
@@ -4192,6 +4146,7 @@
final float density = mBuilder.mContext.getResources().getDisplayMetrics().density;
int topPadding = (int) (5 * density);
int bottomPadding = (int) (13 * density);
+ boolean first = true;
while (i < mTexts.size() && i < rowIds.length) {
CharSequence str = mTexts.get(i);
if (str != null && !str.equals("")) {
@@ -4203,23 +4158,26 @@
}
contentView.setViewPadding(rowIds[i], 0, topPadding, 0,
i == rowIds.length - 1 || i == mTexts.size() - 1 ? bottomPadding : 0);
+ handleInboxImageMargin(contentView, rowIds[i], first);
+ first = false;
}
i++;
}
- handleInboxImageMargin(contentView, rowIds[0]);
return contentView;
}
- private void handleInboxImageMargin(RemoteViews contentView, int id) {
- final int max = mBuilder.mN.extras.getInt(EXTRA_PROGRESS_MAX, 0);
- final boolean ind = mBuilder.mN.extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
- boolean hasProgress = max != 0 || ind;
+ private void handleInboxImageMargin(RemoteViews contentView, int id, boolean first) {
int endMargin = 0;
- if (mTexts.size() > 0 && mBuilder.mN.mLargeIcon != null && !hasProgress) {
- endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
- R.dimen.notification_content_picture_margin);
+ if (first) {
+ final int max = mBuilder.mN.extras.getInt(EXTRA_PROGRESS_MAX, 0);
+ final boolean ind = mBuilder.mN.extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
+ boolean hasProgress = max != 0 || ind;
+ if (mBuilder.mN.mLargeIcon != null && !hasProgress) {
+ endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_picture_margin);
+ }
}
contentView.setViewLayoutMarginEnd(id, endMargin);
}
@@ -4402,13 +4360,11 @@
}
handleImage(view);
// handle the content margin
- int endMargin;
+ int endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_margin_end);;
if (mBuilder.mN.mLargeIcon != null) {
- endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
- R.dimen.notification_content_picture_margin_media);
- } else {
- endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
- R.dimen.notification_content_margin_end);
+ endMargin += mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_picture_margin);
}
view.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
return view;
@@ -4455,6 +4411,214 @@
}
}
+ /**
+ * Notification style for custom views that are decorated by the system
+ *
+ * <p>Instead of providing a notification that is completely custom, a developer can set this
+ * style and still obtain system decorations like the notification header with the expand
+ * affordance and actions.
+ *
+ * <p>Use {@link android.app.Notification.Builder#setCustomContentView(RemoteViews)},
+ * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
+ * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
+ * corresponding custom views to display.
+ *
+ * To use this style with your Notification, feed it to
+ * {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
+ * <pre class="prettyprint">
+ * Notification noti = new Notification.Builder()
+ * .setSmallIcon(R.drawable.ic_stat_player)
+ * .setLargeIcon(albumArtBitmap))
+ * .setCustomContentView(contentView);
+ * .setStyle(<b>new Notification.DecoratedCustomViewStyle()</b>)
+ * .build();
+ * </pre>
+ */
+ public static class DecoratedCustomViewStyle extends Style {
+
+ public DecoratedCustomViewStyle() {
+ }
+
+ public DecoratedCustomViewStyle(Builder builder) {
+ setBuilder(builder);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean displayCustomViewInline() {
+ return true;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeContentView() {
+ return makeStandardTemplateWithCustomContent(mBuilder.mN.contentView);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeBigContentView() {
+ return makeDecoratedBigContentView();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeHeadsUpContentView() {
+ return makeDecoratedHeadsUpContentView();
+ }
+
+ private RemoteViews makeDecoratedHeadsUpContentView() {
+ RemoteViews headsUpContentView = mBuilder.mN.headsUpContentView == null
+ ? mBuilder.mN.contentView
+ : mBuilder.mN.headsUpContentView;
+ if (mBuilder.mActions.size() == 0) {
+ return makeStandardTemplateWithCustomContent(headsUpContentView);
+ }
+ RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions(
+ mBuilder.getBigBaseLayoutResource());
+ buildIntoRemoteViewContent(remoteViews, headsUpContentView);
+ return remoteViews;
+ }
+
+ private RemoteViews makeStandardTemplateWithCustomContent(RemoteViews customContent) {
+ RemoteViews remoteViews = mBuilder.applyStandardTemplate(
+ mBuilder.getBaseLayoutResource());
+ buildIntoRemoteViewContent(remoteViews, customContent);
+ return remoteViews;
+ }
+
+ private RemoteViews makeDecoratedBigContentView() {
+ RemoteViews bigContentView = mBuilder.mN.bigContentView == null
+ ? mBuilder.mN.contentView
+ : mBuilder.mN.bigContentView;
+ if (mBuilder.mActions.size() == 0) {
+ return makeStandardTemplateWithCustomContent(bigContentView);
+ }
+ RemoteViews remoteViews = mBuilder.applyStandardTemplateWithActions(
+ mBuilder.getBigBaseLayoutResource());
+ buildIntoRemoteViewContent(remoteViews, bigContentView);
+ return remoteViews;
+ }
+
+ private void buildIntoRemoteViewContent(RemoteViews remoteViews,
+ RemoteViews customContent) {
+ remoteViews.removeAllViews(R.id.notification_main_column);
+ remoteViews.addView(R.id.notification_main_column, customContent);
+ // also update the end margin if there is an image
+ int endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_margin_end);
+ if (mBuilder.mN.mLargeIcon != null) {
+ endMargin += mBuilder.mContext.getResources().getDimensionPixelSize(
+ R.dimen.notification_content_picture_margin);
+ }
+ remoteViews.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
+ }
+ }
+
+ /**
+ * Notification style for media custom views that are decorated by the system
+ *
+ * <p>Instead of providing a media notification that is completely custom, a developer can set
+ * this style and still obtain system decorations like the notification header with the expand
+ * affordance and actions.
+ *
+ * <p>Use {@link android.app.Notification.Builder#setCustomContentView(RemoteViews)},
+ * {@link android.app.Notification.Builder#setCustomBigContentView(RemoteViews)} and
+ * {@link android.app.Notification.Builder#setCustomHeadsUpContentView(RemoteViews)} to set the
+ * corresponding custom views to display.
+ *
+ * To use this style with your Notification, feed it to
+ * {@link Notification.Builder#setStyle(android.app.Notification.Style)} like so:
+ * <pre class="prettyprint">
+ * Notification noti = new Notification.Builder()
+ * .setSmallIcon(R.drawable.ic_stat_player)
+ * .setLargeIcon(albumArtBitmap))
+ * .setCustomContentView(contentView);
+ * .setStyle(<b>new Notification.DecoratedMediaCustomViewStyle()</b>
+ * .setMediaSession(mySession))
+ * .build();
+ * </pre>
+ *
+ * @see android.app.Notification.DecoratedCustomViewStyle
+ * @see android.app.Notification.MediaStyle
+ */
+ public static class DecoratedMediaCustomViewStyle extends MediaStyle {
+
+ public DecoratedMediaCustomViewStyle() {
+ }
+
+ public DecoratedMediaCustomViewStyle(Builder builder) {
+ setBuilder(builder);
+ }
+
+ /**
+ * @hide
+ */
+ public boolean displayCustomViewInline() {
+ return true;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeContentView() {
+ RemoteViews remoteViews = super.makeContentView();
+ return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
+ mBuilder.mN.contentView);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeBigContentView() {
+ RemoteViews customRemoteView = mBuilder.mN.bigContentView != null
+ ? mBuilder.mN.bigContentView
+ : mBuilder.mN.contentView;
+ return makeBigContentViewWithCustomContent(customRemoteView);
+ }
+
+ private RemoteViews makeBigContentViewWithCustomContent(RemoteViews customRemoteView) {
+ RemoteViews remoteViews = super.makeBigContentView();
+ if (remoteViews != null) {
+ return buildIntoRemoteView(remoteViews, R.id.notification_main_column,
+ customRemoteView);
+ } else if (customRemoteView != mBuilder.mN.contentView){
+ remoteViews = super.makeContentView();
+ return buildIntoRemoteView(remoteViews, R.id.notification_content_container,
+ customRemoteView);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public RemoteViews makeHeadsUpContentView() {
+ RemoteViews customRemoteView = mBuilder.mN.headsUpContentView != null
+ ? mBuilder.mN.headsUpContentView
+ : mBuilder.mN.contentView;
+ return makeBigContentViewWithCustomContent(customRemoteView);
+ }
+
+ private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id,
+ RemoteViews customContent) {
+ remoteViews.removeAllViews(id);
+ remoteViews.addView(id, customContent);
+ return remoteViews;
+ }
+ }
+
// When adding a new Style subclass here, don't forget to update
// Builder.getNotificationStyleClass.
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 1f17024..324a0ab 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -246,6 +246,7 @@
}
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
final Notification copy = notification.clone();
+ Builder.stripForDelivery(copy);
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
copy, idOut, user.getIdentifier());
@@ -506,11 +507,10 @@
return false;
}
- public int getImportance(String topicId) {
- Preconditions.checkNotNull(topicId);
+ public int getImportance() {
INotificationManager service = getService();
try {
- return service.getTopicImportance(mContext.getPackageName(), topicId);
+ return service.getPackageImportance(mContext.getPackageName());
} catch (RemoteException e) {
}
return NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index c552cfc..c1180e2 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -87,20 +87,20 @@
}
new Thread("SharedPreferencesImpl-load") {
public void run() {
- synchronized (SharedPreferencesImpl.this) {
- loadFromDiskLocked();
- }
+ loadFromDisk();
}
}.start();
}
- private void loadFromDiskLocked() {
- if (mLoaded) {
- return;
- }
- if (mBackupFile.exists()) {
- mFile.delete();
- mBackupFile.renameTo(mFile);
+ private void loadFromDisk() {
+ synchronized (SharedPreferencesImpl.this) {
+ if (mLoaded) {
+ return;
+ }
+ if (mBackupFile.exists()) {
+ mFile.delete();
+ mBackupFile.renameTo(mFile);
+ }
}
// Debugging
@@ -118,27 +118,27 @@
str = new BufferedInputStream(
new FileInputStream(mFile), 16*1024);
map = XmlUtils.readMapXml(str);
- } catch (XmlPullParserException e) {
- Log.w(TAG, "getSharedPreferences", e);
- } catch (FileNotFoundException e) {
- Log.w(TAG, "getSharedPreferences", e);
- } catch (IOException e) {
+ } catch (XmlPullParserException | IOException e) {
Log.w(TAG, "getSharedPreferences", e);
} finally {
IoUtils.closeQuietly(str);
}
}
} catch (ErrnoException e) {
+ /* ignore */
}
- mLoaded = true;
- if (map != null) {
- mMap = map;
- mStatTimestamp = stat.st_mtime;
- mStatSize = stat.st_size;
- } else {
- mMap = new HashMap<String, Object>();
+
+ synchronized (SharedPreferencesImpl.this) {
+ mLoaded = true;
+ if (map != null) {
+ mMap = map;
+ mStatTimestamp = stat.st_mtime;
+ mStatSize = stat.st_size;
+ } else {
+ mMap = new HashMap<>();
+ }
+ notifyAll();
}
- notifyAll();
}
static File makeBackupFile(File prefsFile) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5eed781..52fba3b 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -89,6 +89,7 @@
import android.os.DropBoxManager;
import android.os.HardwarePropertiesManager;
import android.os.IBinder;
+import android.os.IHardwarePropertiesManager;
import android.os.IPowerManager;
import android.os.IUserManager;
import android.os.PowerManager;
@@ -715,7 +716,14 @@
new CachedServiceFetcher<HardwarePropertiesManager>() {
@Override
public HardwarePropertiesManager createService(ContextImpl ctx) {
- return new HardwarePropertiesManager();
+ IBinder b = ServiceManager.getService(Context.HARDWARE_PROPERTIES_SERVICE);
+ IHardwarePropertiesManager service =
+ IHardwarePropertiesManager.Stub.asInterface(b);
+ if (service == null) {
+ Log.wtf(TAG, "Failed to get hardwareproperties service.");
+ return null;
+ }
+ return new HardwarePropertiesManager(ctx, service);
}});
registerService(Context.SOUND_TRIGGER_SERVICE, SoundTriggerManager.class,
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index eda82c0..c3512ec 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+h * Copyright (C) 2009 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.
@@ -49,6 +49,7 @@
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;
@@ -265,11 +266,10 @@
private Bitmap mWallpaper;
private Bitmap mDefaultWallpaper;
- private static final int MSG_CLEAR_WALLPAPER = 1;
-
Globals(Looper looper) {
IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
mService = IWallpaperManager.Stub.asInterface(b);
+ forgetLoadedWallpaper();
}
public void onWallpaperChanged() {
@@ -278,13 +278,14 @@
* to null so if the user requests the wallpaper again then we'll
* fetch it.
*/
- synchronized (this) {
- mWallpaper = null;
- mDefaultWallpaper = null;
- }
+ forgetLoadedWallpaper();
}
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
+ return peekWallpaperBitmap(context, returnDefault, context.getUserId());
+ }
+
+ public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault, int userId) {
synchronized (this) {
if (mService != null) {
try {
@@ -303,7 +304,7 @@
}
mWallpaper = null;
try {
- mWallpaper = getCurrentWallpaperLocked(context);
+ mWallpaper = getCurrentWallpaperLocked(userId);
} catch (OutOfMemoryError e) {
Log.w(TAG, "No memory load current wallpaper", e);
}
@@ -326,7 +327,7 @@
}
}
- private Bitmap getCurrentWallpaperLocked(Context context) {
+ private Bitmap getCurrentWallpaperLocked(int userId) {
if (mService == null) {
Log.w(TAG, "WallpaperService not running");
return null;
@@ -334,7 +335,8 @@
try {
Bundle params = new Bundle();
- ParcelFileDescriptor fd = mService.getWallpaper(this, params);
+ ParcelFileDescriptor fd = mService.getWallpaper(this, FLAG_SET_SYSTEM,
+ params, userId);
if (fd != null) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
@@ -633,7 +635,7 @@
* wallpaper or a null pointer if these is none.
*/
public Drawable peekFastDrawable() {
- Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
+ Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, false);
if (bm != null) {
return new FastBitmapDrawable(bm);
}
@@ -646,7 +648,52 @@
* @hide
*/
public Bitmap getBitmap() {
- return sGlobals.peekWallpaperBitmap(mContext, true);
+ return getBitmapAsUser(mContext.getUserId());
+ }
+
+ /**
+ * Like {@link #getDrawable()} but returns a Bitmap for the provided user.
+ *
+ * @hide
+ */
+ public Bitmap getBitmapAsUser(int userId) {
+ return sGlobals.peekWallpaperBitmap(mContext, true, userId);
+ }
+
+ /**
+ * Get an open, readable file descriptor to the given wallpaper image file.
+ * The callee is resopnsible for closing the fd when done ingesting the file.
+ *
+ * <p>If no lock-specific wallpaper has been configured for the given user, then
+ * this method will return {@code null} when requesting {@link #FLAG_SET_LOCK} rather than
+ * returning the system wallpaper's image file.
+ */
+ public ParcelFileDescriptor getWallpaperFile(int which) {
+ return getWallpaperFile(which, mContext.getUserId());
+ }
+
+ /**
+ * Version of {@link #getWallpaperFile(int)} that can access the wallpaper data
+ * for a given user. The caller must hold the INTERACT_ACROSS_USERS_FULL
+ * permission to access another user's wallpaper data.
+ * @hide
+ */
+ public ParcelFileDescriptor getWallpaperFile(int which, int userId) {
+ if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ throw new IllegalArgumentException("Must request exactly one kind of wallpaper");
+ }
+
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return null;
+ } else {
+ try {
+ Bundle outParams = new Bundle();
+ return sGlobals.mService.getWallpaper(null, which, outParams, userId);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
}
/**
@@ -656,9 +703,7 @@
* wallpaper will require reloading it again from disk.
*/
public void forgetLoadedWallpaper() {
- if (isWallpaperSupported()) {
- sGlobals.forgetLoadedWallpaper();
- }
+ sGlobals.forgetLoadedWallpaper();
}
/**
@@ -1209,12 +1254,23 @@
*/
@SystemApi
public void clearWallpaper() {
+ clearWallpaper(FLAG_SET_SYSTEM, mContext.getUserId());
+ }
+
+ /**
+ * Clear the wallpaper for a specific user. The caller must hold the
+ * INTERACT_ACROSS_USERS_FULL permission to clear another user's
+ * wallpaper.
+ * @hide
+ */
+ @SystemApi
+ public void clearWallpaper(int which, int userId) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
return;
}
try {
- sGlobals.mService.clearWallpaper(mContext.getOpPackageName());
+ sGlobals.mService.clearWallpaper(mContext.getOpPackageName(), which, userId);
} catch (RemoteException e) {
// Ignore
}
@@ -1363,7 +1419,7 @@
}
/**
- * Remove any currently set wallpaper, reverting to the system's built-in
+ * Remove any currently set system wallpaper, reverting to the system's built-in
* wallpaper. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
* is broadcast.
*
@@ -1424,6 +1480,26 @@
return null;
}
+ /**
+ * Register a callback for lock wallpaper observation. Only the OS may use this.
+ *
+ * @return true on success; false on error.
+ * @hide
+ */
+ public boolean setLockWallpaperCallback(IWallpaperManagerCallback callback) {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return false;
+ }
+
+ try {
+ return sGlobals.mService.setLockWallpaperCallback(callback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to contact wallpaper service");
+ }
+ return false;
+ }
+
// Private completion callback for setWallpaper() synchronization
private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
final CountDownLatch mLatch;
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 34dfb26..d5ca0e9 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -117,8 +117,8 @@
= "android.app.action.DEVICE_ADMIN_DISABLED";
/**
- * Action sent to a device administrator when the user has changed the
- * password of their device. You can at this point check the characteristics
+ * Action sent to a device administrator when the user has changed the password of their device
+ * or profile challenge. You can at this point check the characteristics
* of the new password with {@link DevicePolicyManager#isActivePasswordSufficient()
* DevicePolicyManager.isActivePasswordSufficient()}.
* You will generally
@@ -133,8 +133,8 @@
= "android.app.action.ACTION_PASSWORD_CHANGED";
/**
- * Action sent to a device administrator when the user has failed at
- * attempted to enter the password. You can at this point check the
+ * Action sent to a device administrator when the user has entered an incorrect device
+ * or profile challenge password. You can at this point check the
* number of failed password attempts there have been with
* {@link DevicePolicyManager#getCurrentFailedPasswordAttempts
* DevicePolicyManager.getCurrentFailedPasswordAttempts()}. You will generally
@@ -149,8 +149,9 @@
= "android.app.action.ACTION_PASSWORD_FAILED";
/**
- * Action sent to a device administrator when the user has successfully
- * entered their password, after failing one or more times.
+ * Action sent to a device administrator when the user has successfully entered their device
+ * or profile challenge password, after failing one or more times. You will generally
+ * handle this in {@link DeviceAdminReceiver#onPasswordSucceeded}.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to receive
@@ -161,8 +162,9 @@
= "android.app.action.ACTION_PASSWORD_SUCCEEDED";
/**
- * Action periodically sent to a device administrator when the device password
- * is expiring.
+ * Action periodically sent to a device administrator when the device or profile challenge
+ * password is expiring. You will generally
+ * handle this in {@link DeviceAdminReceiver#onPasswordExpiring}.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_EXPIRE_PASSWORD} to receive
@@ -417,7 +419,7 @@
}
/**
- * Called after the user has changed their password, as a result of
+ * Called after the user has changed their device or profile challenge password, as a result of
* receiving {@link #ACTION_PASSWORD_CHANGED}. At this point you
* can use {@link DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
* to retrieve the active password characteristics.
@@ -428,10 +430,10 @@
}
/**
- * Called after the user has failed at entering their current password, as a result of
- * receiving {@link #ACTION_PASSWORD_FAILED}. At this point you
- * can use {@link DevicePolicyManager} to retrieve the number of failed
- * password attempts.
+ * Called after the user has failed at entering their device or profile challenge password,
+ * as a result of receiving {@link #ACTION_PASSWORD_FAILED}. At this point you can use
+ * {@link DevicePolicyManager#getCurrentFailedPasswordAttempts()} to retrieve the number of
+ * failed password attempts.
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
*/
@@ -439,7 +441,7 @@
}
/**
- * Called after the user has succeeded at entering their current password,
+ * Called after the user has succeeded at entering their device or profile challenge password,
* as a result of receiving {@link #ACTION_PASSWORD_SUCCEEDED}. This will
* only be received the first time they succeed after having previously
* failed.
@@ -450,9 +452,9 @@
}
/**
- * Called periodically when the password is about to expire or has expired. It will typically
- * be called at these times: on device boot, once per day before the password expires,
- * and at the time when the password expires.
+ * Called periodically when the device or profile challenge password is about to expire
+ * or has expired. It will typically be called at these times: on device boot, once per day
+ * before the password expires, and at the time when the password expires.
*
* <p>If the password is not updated by the user, this method will continue to be called
* once per day until the password is changed or the device admin disables password expiration.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 7e7c5ec..ae63a2f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -849,6 +849,8 @@
* this will trigger entering a new password for the parent of the profile.
* For all other cases it will trigger entering a new password for the user
* or profile it is launched from.
+ *
+ * @see #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SET_NEW_PASSWORD
@@ -1188,7 +1190,8 @@
* restrictive as what has been set. Note that the current password
* will remain until the user has set a new one, so the change does not
* take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value.
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after calling this method.
*
* <p>Quality constants are ordered so that higher values are more restrictive;
* thus the highest requested quality constant (between the policy set here,
@@ -1199,6 +1202,10 @@
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param quality The new desired quality. One of
* {@link #PASSWORD_QUALITY_UNSPECIFIED}, {@link #PASSWORD_QUALITY_SOMETHING},
@@ -1217,8 +1224,14 @@
}
/**
- * Retrieve the current minimum password quality for all admins of this user
- * and its profiles or a particular one.
+ * Retrieve the current minimum password quality for a particular admin or all admins that set
+ * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
*/
@@ -1245,7 +1258,8 @@
* restrictive as what has been set. Note that the current password
* will remain until the user has set a new one, so the change does not
* take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested either
* {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX},
* {@link #PASSWORD_QUALITY_ALPHABETIC}, {@link #PASSWORD_QUALITY_ALPHANUMERIC},
@@ -1255,6 +1269,10 @@
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param length The new desired minimum password length. A value of 0
* means there is no restriction.
@@ -1270,7 +1288,14 @@
}
/**
- * Retrieve the current minimum password length for all admins of this
+ * Retrieve the current minimum password length for a particular admin or all admins that set
+ * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* user and its profiles or a particular one.
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
@@ -1298,7 +1323,8 @@
* not at least as restrictive as what has been set. Note that the current
* password will remain until the user has set a new one, so the change does
* not take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 0.
@@ -1307,6 +1333,10 @@
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of upper case letters
@@ -1324,13 +1354,19 @@
}
/**
- * Retrieve the current number of upper case letters required in the
- * password for all admins of this user and its profiles or a particular one.
+ * Retrieve the current number of upper case letters required in the password
+ * for a particular admin or all admins that set retrictions on this user and
+ * its participating profiles. Restrictions on profiles that have a separate challenge
+ * are not taken into account.
* This is the same value as set by
- * {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)}
+ * {@link #setPasswordMinimumUpperCase(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of upper case letters required in the
@@ -1359,7 +1395,8 @@
* not at least as restrictive as what has been set. Note that the current
* password will remain until the user has set a new one, so the change does
* not take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 0.
@@ -1368,6 +1405,10 @@
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of lower case letters
@@ -1385,13 +1426,19 @@
}
/**
- * Retrieve the current number of lower case letters required in the
- * password for all admins of this user and its profiles or a particular one.
+ * Retrieve the current number of lower case letters required in the password
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
* This is the same value as set by
- * {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)}
+ * {@link #setPasswordMinimumLowerCase(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of lower case letters required in the
@@ -1420,7 +1467,8 @@
* restrictive as what has been set. Note that the current password will
* remain until the user has set a new one, so the change does not take
* place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 1.
@@ -1429,6 +1477,10 @@
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of letters required in the
@@ -1445,12 +1497,19 @@
}
/**
- * Retrieve the current number of letters required in the password for all
- * admins or a particular one. This is the same value as
- * set by {#link {@link #setPasswordMinimumLetters(ComponentName, int)}
+ * Retrieve the current number of letters required in the password
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
+ * This is the same value as set by
+ * {@link #setPasswordMinimumLetters(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of letters required in the password.
@@ -1478,7 +1537,8 @@
* not at least as restrictive as what has been set. Note that the current
* password will remain until the user has set a new one, so the change does
* not take place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 1.
@@ -1487,6 +1547,10 @@
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of numerical digits required
@@ -1504,12 +1568,18 @@
/**
* Retrieve the current number of numerical digits required in the password
- * for all admins of this user and its profiles or a particular one.
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
* This is the same value as set by
- * {#link {@link #setPasswordMinimumNumeric(ComponentName, int)}
+ * {@link #setPasswordMinimumNumeric(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of numerical digits required in the password.
@@ -1537,7 +1607,8 @@
* restrictive as what has been set. Note that the current password will
* remain until the user has set a new one, so the change does not take
* place immediately. To prompt the user for a new password, use
- * {@link #ACTION_SET_NEW_PASSWORD} after setting this value. This
+ * {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value. This
* constraint is only imposed if the administrator has also requested
* {@link #PASSWORD_QUALITY_COMPLEX} with {@link #setPasswordQuality}. The
* default value is 1.
@@ -1546,6 +1617,10 @@
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of symbols required in the
@@ -1562,12 +1637,18 @@
}
/**
- * Retrieve the current number of symbols required in the password for all
- * admins or a particular one. This is the same value as
- * set by {#link {@link #setPasswordMinimumSymbols(ComponentName, int)}
+ * Retrieve the current number of symbols required in the password
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account. This is the same value as
+ * set by {@link #setPasswordMinimumSymbols(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of symbols required in the password.
@@ -1595,7 +1676,8 @@
* to enter a new password that is not at least as restrictive as what has
* been set. Note that the current password will remain until the user has
* set a new one, so the change does not take place immediately. To prompt
- * the user for a new password, use {@link #ACTION_SET_NEW_PASSWORD} after
+ * the user for a new password, use {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after
* setting this value. This constraint is only imposed if the administrator
* has also requested {@link #PASSWORD_QUALITY_COMPLEX} with
* {@link #setPasswordQuality}. The default value is 0.
@@ -1604,6 +1686,10 @@
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired minimum number of letters required in the
@@ -1620,13 +1706,19 @@
}
/**
- * Retrieve the current number of non-letter characters required in the
- * password for all admins of this user and its profiles or a particular one.
+ * Retrieve the current number of non-letter characters required in the password
+ * for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
* This is the same value as set by
- * {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)}
+ * {@link #setPasswordMinimumNonLetter(ComponentName, int)}
* and only applies when the password quality is
* {@link #PASSWORD_QUALITY_COMPLEX}.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to
* aggregate all admins.
* @return The minimum number of letters required in the password.
@@ -1653,7 +1745,8 @@
* enter a new password that is the same as any password in the history. Note
* that the current password will remain until the user has set a new one, so
* the change does not take place immediately. To prompt the user for a new
- * password, use {@link #ACTION_SET_NEW_PASSWORD} after setting this value.
+ * password, use {@link #ACTION_SET_NEW_PASSWORD} or
+ * {@link #ACTION_SET_NEW_PARENT_PROFILE_PASSWORD} after setting this value.
* This constraint is only imposed if the administrator has also requested
* either {@link #PASSWORD_QUALITY_NUMERIC}, {@link #PASSWORD_QUALITY_NUMERIC_COMPLEX}
* {@link #PASSWORD_QUALITY_ALPHABETIC}, or {@link #PASSWORD_QUALITY_ALPHANUMERIC}
@@ -1664,6 +1757,10 @@
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this
* method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated
* with.
* @param length The new desired length of password history. A value of 0
@@ -1697,6 +1794,10 @@
* <p> Note that setting the password will automatically reset the expiration time for all
* active admins. Active admins do not need to explicitly call this method in that case.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param timeout The limit (in ms) that a password can remain in effect. A value of 0
* means there is no restriction (unlimited).
@@ -1715,7 +1816,12 @@
* Get the password expiration timeout for the given admin. The expiration timeout is the
* recurring expiration timeout provided in the call to
* {@link #setPasswordExpirationTimeout(ComponentName, long)} for the given admin or the
- * aggregate of all policy administrators if {@code admin} is null.
+ * aggregate of all participating policy administrators if {@code admin} is null. Admins that
+ * have set restrictions on profiles that have a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
*
* @param admin The name of the admin component to check, or {@code null} to aggregate all admins.
* @return The timeout for the given admin or the minimum of all timeouts
@@ -1732,14 +1838,17 @@
}
/**
- * Get the current password expiration time for the given admin or an aggregate of
- * all admins of this user and its profiles if admin is null. If the password is
- * expired, this will return the time since the password expired as a negative number.
- * If admin is null, then a composite of all expiration timeouts is returned
- * - which will be the minimum of all timeouts.
+ * Get the current password expiration time for a particular admin or all admins that set
+ * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account. If admin is {@code null}, then a composite
+ * of all expiration times is returned - which will be the minimum of all of them.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * the password expiration for the parent profile.
*
* @param admin The name of the admin component to check, or {@code null} to aggregate all admins.
- * @return The password expiration time, in ms.
+ * @return The password expiration time, in milliseconds since epoch.
*/
public long getPasswordExpiration(@Nullable ComponentName admin) {
if (mService != null) {
@@ -1753,8 +1862,14 @@
}
/**
- * Retrieve the current password history length for all admins of this
- * user and its profiles or a particular one.
+ * Retrieve the current password history length for a particular admin or all admins that
+ * set retrictions on this user and its participating profiles. Restrictions on profiles that
+ * have a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
* @return The length of the password history
@@ -1788,13 +1903,18 @@
/**
* Determine whether the current password the user has set is sufficient
- * to meet the policy requirements (quality, minimum length) that have been
- * requested by the admins of this user and its profiles that don't have a separate challenge.
+ * to meet the policy requirements (e.g. quality, minimum length) that have been
+ * requested by the admins of this user and its participating profiles.
+ * Restrictions on profiles that have a separate challenge are not taken into account.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to determine
+ * if the password set on the parent profile is sufficient.
+ *
* @return Returns true if the password meets the current requirements, else false.
*/
public boolean isActivePasswordSufficient() {
@@ -1810,7 +1930,7 @@
/**
* Determine whether the current profile password the user has set is sufficient
- * to meet the policy requirements (quality, minimum length) that have been
+ * to meet the policy requirements (e.g. quality, minimum length) that have been
* requested by the admins of the parent user and its profiles.
*
* @param userHandle the userId of the profile to check the password for.
@@ -1832,6 +1952,10 @@
* Retrieve the number of times the user has failed at entering a
* password since that last successful password entry.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * the number of failed password attemts for the parent user.
+ *
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} to be able to call
* this method; if it has not, a security exception will be thrown.
@@ -1880,7 +2004,7 @@
/**
* Setting this to a value greater than zero enables a built-in policy
- * that will perform a device wipe after too many incorrect
+ * that will perform a device or profile wipe after too many incorrect
* device-unlock passwords have been entered. This built-in policy combines
* watching for failed passwords and wiping the device, and requires
* that you request both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
@@ -1891,11 +2015,15 @@
* failure to a server), you should implement
* {@link DeviceAdminReceiver#onPasswordFailed(Context, android.content.Intent)}
* instead. Do not use this API, because if the maximum count is reached,
- * the device will be wiped immediately, and your callback will not be invoked.
+ * the device or profile will be wiped immediately, and your callback will not be invoked.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * a value on the parent profile.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param num The number of failed password attempts at which point the
- * device will wipe its data.
+ * device or profile will be wiped.
*/
public void setMaximumFailedPasswordsForWipe(@NonNull ComponentName admin, int num) {
if (mService != null) {
@@ -1908,9 +2036,15 @@
}
/**
- * Retrieve the current maximum number of login attempts that are allowed
- * before the device wipes itself, for all admins of this user and its profiles
- * or a particular one.
+ * Retrieve the current maximum number of login attempts that are allowed before the device
+ * or profile is wiped, for a particular admin or all admins that set retrictions on this user
+ * and its participating profiles. Restrictions on profiles that have a separate challenge are
+ * not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * the value for the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
*/
@@ -2027,6 +2161,10 @@
* {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
* this method; if it has not, a security exception will be thrown.
*
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param timeMs The new desired maximum time to lock in milliseconds.
* A value of 0 means there is no restriction.
@@ -2042,8 +2180,14 @@
}
/**
- * Retrieve the current maximum time to unlock for all admins of this user
- * and its profiles or a particular one.
+ * Retrieve the current maximum time to unlock for a particular admin or all admins that set
+ * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to aggregate
* all admins.
* @return time in milliseconds for the given admin or the minimum value (strictest) of
@@ -2072,6 +2216,10 @@
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK} to be able to call
* this method; if it has not, a security exception will be thrown.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to lock
+ * the parent profile.
*/
public void lockNow() {
if (mService != null) {
@@ -2570,7 +2718,7 @@
try {
return mService.removeKeyPair(admin, alias);
} catch (RemoteException e) {
- Log.w(TAG, "Failed talking with device policy service", e);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
return false;
}
@@ -2893,17 +3041,25 @@
* this method; if it has not, a security exception will be thrown.
*
* <p>Calling this from a managed profile before version
- * {@link android.os.Build.VERSION_CODES#M} will throw a security exception.
- *
- * <p>From version {@link android.os.Build.VERSION_CODES#M} a profile owner can set:
+ * {@link android.os.Build.VERSION_CODES#M} will throw a security exception. From version
+ * {@link android.os.Build.VERSION_CODES#M} the profile owner of a managed profile can set:
* <ul>
- * <li>{@link #KEYGUARD_DISABLE_TRUST_AGENTS}, {@link #KEYGUARD_DISABLE_FINGERPRINT}
- * these will affect the profile's parent user.
- * <li>{@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS} this will affect notifications
- * generated by applications in the managed profile.
+ * <li>{@link #KEYGUARD_DISABLE_TRUST_AGENTS}, which affects the parent user, but only if there
+ * is no separate challenge set on the managed profile.
+ * <li>{@link #KEYGUARD_DISABLE_FINGERPRINT} which affects the managed profile challenge if
+ * there is one, or the parent user otherwise.
+ * <li>{@link #KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS} which affects notifications
+ * generated by applications in the managed profile.
* </ul>
- * <p>Requests to disable other features on a managed profile will be ignored. The admin
- * can check which features have been disabled by calling
+ *
+ * {@link #KEYGUARD_DISABLE_TRUST_AGENTS} and {@link #KEYGUARD_DISABLE_FINGERPRINT} can also be
+ * set on the {@link DevicePolicyManager} instance returned by
+ * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the
+ * parent profile.
+ *
+ * <p>Requests to disable other features on a managed profile will be ignored.
+ *
+ * <p>The admin can check which features have been disabled by calling
* {@link #getKeyguardDisabledFeatures(ComponentName)}
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -2925,7 +3081,13 @@
/**
* Determine whether or not features have been disabled in keyguard either by the calling
- * admin, if specified, or all admins.
+ * admin, if specified, or all admins that set retrictions on this user and its participating
+ * profiles. Restrictions on profiles that have a separate challenge are not taken into account.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
* @param admin The name of the admin component to check, or {@code null} to check whether any
* admins have disabled features in keyguard.
* @return bitfield of flags. See {@link #setKeyguardDisabledFeatures(ComponentName, int)}
@@ -3502,7 +3664,7 @@
try {
return mService.setPackagesSuspended(admin, packageNames, suspended);
} catch (RemoteException re) {
- Log.w(TAG, "Failed talking with device policy service", re);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
}
}
return packageNames;
@@ -3521,7 +3683,7 @@
try {
return mService.getPackageSuspended(admin, packageName);
} catch (RemoteException e) {
- Log.w(TAG, "Failed talking with device policy service", e);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
}
return false;
@@ -5786,7 +5948,7 @@
try {
mService.setAffiliationIds(admin, new ArrayList<String>(ids));
} catch (RemoteException e) {
- Log.w(TAG, "Failed talking with device policy service", e);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
}
@@ -5801,7 +5963,7 @@
try {
return mService != null && mService.isAffiliatedUser();
} catch (RemoteException e) {
- Log.w(TAG, "Failed talking with device policy service", e);
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
return false;
}
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 63f1425..aeb3156 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -308,14 +308,31 @@
final String packageName = getPackageName();
final ApplicationInfo appInfo = getApplicationInfo();
- String rootDir = new File(appInfo.dataDir).getCanonicalPath();
- String filesDir = getFilesDir().getCanonicalPath();
- String nobackupDir = getNoBackupFilesDir().getCanonicalPath();
- String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
- String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
- String cacheDir = getCacheDir().getCanonicalPath();
- String codeCacheDir = getCodeCacheDir().getCanonicalPath();
- String libDir = (appInfo.nativeLibraryDir != null)
+ // System apps have control over where their default storage context
+ // is pointed, so we're always explicit when building paths.
+ final Context ceContext = createCredentialEncryptedStorageContext();
+ final String rootDir = ceContext.getDataDir().getCanonicalPath();
+ final String filesDir = ceContext.getFilesDir().getCanonicalPath();
+ final String noBackupDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
+ final String databaseDir = ceContext.getDatabasePath("foo").getParentFile()
+ .getCanonicalPath();
+ final String sharedPrefsDir = ceContext.getSharedPreferencesPath("foo").getParentFile()
+ .getCanonicalPath();
+ final String cacheDir = ceContext.getCacheDir().getCanonicalPath();
+ final String codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();
+
+ final Context deContext = createDeviceEncryptedStorageContext();
+ final String deviceRootDir = deContext.getDataDir().getCanonicalPath();
+ final String deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
+ final String deviceNoBackupDir = deContext.getNoBackupFilesDir().getCanonicalPath();
+ final String deviceDatabaseDir = deContext.getDatabasePath("foo").getParentFile()
+ .getCanonicalPath();
+ final String deviceSharedPrefsDir = deContext.getSharedPreferencesPath("foo")
+ .getParentFile().getCanonicalPath();
+ final String deviceCacheDir = deContext.getCacheDir().getCanonicalPath();
+ final String deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath();
+
+ final String libDir = (appInfo.nativeLibraryDir != null)
? new File(appInfo.nativeLibraryDir).getCanonicalPath()
: null;
@@ -325,30 +342,48 @@
final ArraySet<String> traversalExcludeSet = new ArraySet<String>();
// Add the directories we always exclude.
+ traversalExcludeSet.add(filesDir);
+ traversalExcludeSet.add(noBackupDir);
+ traversalExcludeSet.add(databaseDir);
+ traversalExcludeSet.add(sharedPrefsDir);
traversalExcludeSet.add(cacheDir);
traversalExcludeSet.add(codeCacheDir);
- traversalExcludeSet.add(nobackupDir);
+
+ traversalExcludeSet.add(deviceFilesDir);
+ traversalExcludeSet.add(deviceNoBackupDir);
+ traversalExcludeSet.add(deviceDatabaseDir);
+ traversalExcludeSet.add(deviceSharedPrefsDir);
+ traversalExcludeSet.add(deviceCacheDir);
+ traversalExcludeSet.add(deviceCodeCacheDir);
+
if (libDir != null) {
traversalExcludeSet.add(libDir);
}
- traversalExcludeSet.add(databaseDir);
- traversalExcludeSet.add(sharedPrefsDir);
- traversalExcludeSet.add(filesDir);
-
// Root dir first.
applyXmlFiltersAndDoFullBackupForDomain(
packageName, FullBackup.ROOT_TREE_TOKEN, manifestIncludeMap,
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(rootDir);
+ applyXmlFiltersAndDoFullBackupForDomain(
+ packageName, FullBackup.DEVICE_ROOT_TREE_TOKEN, manifestIncludeMap,
+ manifestExcludeSet, traversalExcludeSet, data);
+ traversalExcludeSet.add(deviceRootDir);
+
// Data dir next.
traversalExcludeSet.remove(filesDir);
applyXmlFiltersAndDoFullBackupForDomain(
- packageName, FullBackup.DATA_TREE_TOKEN, manifestIncludeMap,
+ packageName, FullBackup.FILES_TREE_TOKEN, manifestIncludeMap,
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(filesDir);
+ traversalExcludeSet.remove(deviceFilesDir);
+ applyXmlFiltersAndDoFullBackupForDomain(
+ packageName, FullBackup.DEVICE_FILES_TREE_TOKEN, manifestIncludeMap,
+ manifestExcludeSet, traversalExcludeSet, data);
+ traversalExcludeSet.add(deviceFilesDir);
+
// Database directory.
traversalExcludeSet.remove(databaseDir);
applyXmlFiltersAndDoFullBackupForDomain(
@@ -356,6 +391,12 @@
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(databaseDir);
+ traversalExcludeSet.remove(deviceDatabaseDir);
+ applyXmlFiltersAndDoFullBackupForDomain(
+ packageName, FullBackup.DEVICE_DATABASE_TREE_TOKEN, manifestIncludeMap,
+ manifestExcludeSet, traversalExcludeSet, data);
+ traversalExcludeSet.add(deviceDatabaseDir);
+
// SharedPrefs.
traversalExcludeSet.remove(sharedPrefsDir);
applyXmlFiltersAndDoFullBackupForDomain(
@@ -363,6 +404,12 @@
manifestExcludeSet, traversalExcludeSet, data);
traversalExcludeSet.add(sharedPrefsDir);
+ traversalExcludeSet.remove(deviceSharedPrefsDir);
+ applyXmlFiltersAndDoFullBackupForDomain(
+ packageName, FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN, manifestIncludeMap,
+ manifestExcludeSet, traversalExcludeSet, data);
+ traversalExcludeSet.add(deviceSharedPrefsDir);
+
// getExternalFilesDir() location associated with this app. Technically there should
// not be any files here if the app does not properly have permission to access
// external storage, but edge cases happen. fullBackupFileTree() catches
@@ -445,27 +492,49 @@
*/
public final void fullBackupFile(File file, FullBackupDataOutput output) {
// Look up where all of our various well-defined dir trees live on this device
- String mainDir;
- String filesDir;
- String nbFilesDir;
- String dbDir;
- String spDir;
- String cacheDir;
- String codeCacheDir;
- String libDir;
+ final String rootDir;
+ final String filesDir;
+ final String nbFilesDir;
+ final String dbDir;
+ final String spDir;
+ final String cacheDir;
+ final String codeCacheDir;
+ final String deviceRootDir;
+ final String deviceFilesDir;
+ final String deviceNbFilesDir;
+ final String deviceDbDir;
+ final String deviceSpDir;
+ final String deviceCacheDir;
+ final String deviceCodeCacheDir;
+ final String libDir;
+
String efDir = null;
String filePath;
ApplicationInfo appInfo = getApplicationInfo();
try {
- mainDir = new File(appInfo.dataDir).getCanonicalPath();
- filesDir = getFilesDir().getCanonicalPath();
- nbFilesDir = getNoBackupFilesDir().getCanonicalPath();
- dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
- spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
- cacheDir = getCacheDir().getCanonicalPath();
- codeCacheDir = getCodeCacheDir().getCanonicalPath();
+ // System apps have control over where their default storage context
+ // is pointed, so we're always explicit when building paths.
+ final Context ceContext = createCredentialEncryptedStorageContext();
+ rootDir = ceContext.getDataDir().getCanonicalPath();
+ filesDir = ceContext.getFilesDir().getCanonicalPath();
+ nbFilesDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
+ dbDir = ceContext.getDatabasePath("foo").getParentFile().getCanonicalPath();
+ spDir = ceContext.getSharedPreferencesPath("foo").getParentFile().getCanonicalPath();
+ cacheDir = ceContext.getCacheDir().getCanonicalPath();
+ codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();
+
+ final Context deContext = createDeviceEncryptedStorageContext();
+ deviceRootDir = deContext.getDataDir().getCanonicalPath();
+ deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
+ deviceNbFilesDir = deContext.getNoBackupFilesDir().getCanonicalPath();
+ deviceDbDir = deContext.getDatabasePath("foo").getParentFile().getCanonicalPath();
+ deviceSpDir = deContext.getSharedPreferencesPath("foo").getParentFile()
+ .getCanonicalPath();
+ deviceCacheDir = deContext.getCacheDir().getCanonicalPath();
+ deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath();
+
libDir = (appInfo.nativeLibraryDir == null)
? null
: new File(appInfo.nativeLibraryDir).getCanonicalPath();
@@ -489,8 +558,11 @@
if (filePath.startsWith(cacheDir)
|| filePath.startsWith(codeCacheDir)
- || filePath.startsWith(libDir)
- || filePath.startsWith(nbFilesDir)) {
+ || filePath.startsWith(nbFilesDir)
+ || filePath.startsWith(deviceCacheDir)
+ || filePath.startsWith(deviceCodeCacheDir)
+ || filePath.startsWith(deviceNbFilesDir)
+ || filePath.startsWith(libDir)) {
Log.w(TAG, "lib, cache, code_cache, and no_backup files are not backed up");
return;
}
@@ -504,11 +576,23 @@
domain = FullBackup.SHAREDPREFS_TREE_TOKEN;
rootpath = spDir;
} else if (filePath.startsWith(filesDir)) {
- domain = FullBackup.DATA_TREE_TOKEN;
+ domain = FullBackup.FILES_TREE_TOKEN;
rootpath = filesDir;
- } else if (filePath.startsWith(mainDir)) {
+ } else if (filePath.startsWith(rootDir)) {
domain = FullBackup.ROOT_TREE_TOKEN;
- rootpath = mainDir;
+ rootpath = rootDir;
+ } else if (filePath.startsWith(deviceDbDir)) {
+ domain = FullBackup.DEVICE_DATABASE_TREE_TOKEN;
+ rootpath = deviceDbDir;
+ } else if (filePath.startsWith(deviceSpDir)) {
+ domain = FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN;
+ rootpath = deviceSpDir;
+ } else if (filePath.startsWith(deviceFilesDir)) {
+ domain = FullBackup.DEVICE_FILES_TREE_TOKEN;
+ rootpath = deviceFilesDir;
+ } else if (filePath.startsWith(deviceRootDir)) {
+ domain = FullBackup.DEVICE_ROOT_TREE_TOKEN;
+ rootpath = deviceRootDir;
} else if ((efDir != null) && filePath.startsWith(efDir)) {
domain = FullBackup.MANAGED_EXTERNAL_TREE_TOKEN;
rootpath = efDir;
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 9ea2ba2..cdc80e3 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -55,13 +55,22 @@
public static final String APK_TREE_TOKEN = "a";
public static final String OBB_TREE_TOKEN = "obb";
+
public static final String ROOT_TREE_TOKEN = "r";
- public static final String DATA_TREE_TOKEN = "f";
+ public static final String FILES_TREE_TOKEN = "f";
public static final String NO_BACKUP_TREE_TOKEN = "nb";
public static final String DATABASE_TREE_TOKEN = "db";
public static final String SHAREDPREFS_TREE_TOKEN = "sp";
- public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef";
public static final String CACHE_TREE_TOKEN = "c";
+
+ public static final String DEVICE_ROOT_TREE_TOKEN = "d_r";
+ public static final String DEVICE_FILES_TREE_TOKEN = "d_f";
+ public static final String DEVICE_NO_BACKUP_TREE_TOKEN = "d_nb";
+ public static final String DEVICE_DATABASE_TREE_TOKEN = "d_db";
+ public static final String DEVICE_SHAREDPREFS_TREE_TOKEN = "d_sp";
+ public static final String DEVICE_CACHE_TREE_TOKEN = "d_c";
+
+ public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef";
public static final String SHARED_STORAGE_TOKEN = "shared";
public static final String APPS_PREFIX = "apps/";
@@ -201,10 +210,18 @@
private final File DATABASE_DIR;
private final File ROOT_DIR;
private final File SHAREDPREF_DIR;
- private final File EXTERNAL_DIR;
private final File CACHE_DIR;
private final File NOBACKUP_DIR;
+ private final File DEVICE_FILES_DIR;
+ private final File DEVICE_DATABASE_DIR;
+ private final File DEVICE_ROOT_DIR;
+ private final File DEVICE_SHAREDPREF_DIR;
+ private final File DEVICE_CACHE_DIR;
+ private final File DEVICE_NOBACKUP_DIR;
+
+ private final File EXTERNAL_DIR;
+
final int mFullBackupContent;
final PackageManager mPackageManager;
final String mPackageName;
@@ -214,7 +231,7 @@
*/
String tokenToDirectoryPath(String domainToken) {
try {
- if (domainToken.equals(FullBackup.DATA_TREE_TOKEN)) {
+ if (domainToken.equals(FullBackup.FILES_TREE_TOKEN)) {
return FILES_DIR.getCanonicalPath();
} else if (domainToken.equals(FullBackup.DATABASE_TREE_TOKEN)) {
return DATABASE_DIR.getCanonicalPath();
@@ -224,14 +241,26 @@
return SHAREDPREF_DIR.getCanonicalPath();
} else if (domainToken.equals(FullBackup.CACHE_TREE_TOKEN)) {
return CACHE_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.NO_BACKUP_TREE_TOKEN)) {
+ return NOBACKUP_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_FILES_TREE_TOKEN)) {
+ return DEVICE_FILES_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_DATABASE_TREE_TOKEN)) {
+ return DEVICE_DATABASE_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_ROOT_TREE_TOKEN)) {
+ return DEVICE_ROOT_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN)) {
+ return DEVICE_SHAREDPREF_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_CACHE_TREE_TOKEN)) {
+ return DEVICE_CACHE_DIR.getCanonicalPath();
+ } else if (domainToken.equals(FullBackup.DEVICE_NO_BACKUP_TREE_TOKEN)) {
+ return DEVICE_NOBACKUP_DIR.getCanonicalPath();
} else if (domainToken.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)) {
if (EXTERNAL_DIR != null) {
return EXTERNAL_DIR.getCanonicalPath();
} else {
return null;
}
- } else if (domainToken.equals(FullBackup.NO_BACKUP_TREE_TOKEN)) {
- return NOBACKUP_DIR.getCanonicalPath();
}
// Not a supported location
Log.i(TAG, "Unrecognized domain " + domainToken);
@@ -257,12 +286,25 @@
mFullBackupContent = context.getApplicationInfo().fullBackupContent;
mPackageManager = context.getPackageManager();
mPackageName = context.getPackageName();
- FILES_DIR = context.getFilesDir();
- DATABASE_DIR = context.getDatabasePath("foo").getParentFile();
- ROOT_DIR = new File(context.getApplicationInfo().dataDir);
- SHAREDPREF_DIR = context.getSharedPrefsFile("foo").getParentFile();
- CACHE_DIR = context.getCacheDir();
- NOBACKUP_DIR = context.getNoBackupFilesDir();
+
+ // System apps have control over where their default storage context
+ // is pointed, so we're always explicit when building paths.
+ final Context ceContext = context.createCredentialEncryptedStorageContext();
+ FILES_DIR = ceContext.getFilesDir();
+ DATABASE_DIR = ceContext.getDatabasePath("foo").getParentFile();
+ ROOT_DIR = ceContext.getDataDir();
+ SHAREDPREF_DIR = ceContext.getSharedPreferencesPath("foo").getParentFile();
+ CACHE_DIR = ceContext.getCacheDir();
+ NOBACKUP_DIR = ceContext.getNoBackupFilesDir();
+
+ final Context deContext = context.createDeviceEncryptedStorageContext();
+ DEVICE_FILES_DIR = deContext.getFilesDir();
+ DEVICE_DATABASE_DIR = deContext.getDatabasePath("foo").getParentFile();
+ DEVICE_ROOT_DIR = deContext.getDataDir();
+ DEVICE_SHAREDPREF_DIR = deContext.getSharedPreferencesPath("foo").getParentFile();
+ DEVICE_CACHE_DIR = deContext.getCacheDir();
+ DEVICE_NOBACKUP_DIR = deContext.getNoBackupFilesDir();
+
if (android.os.Process.myUid() != Process.SYSTEM_UID) {
EXTERNAL_DIR = context.getExternalFilesDir(null);
} else {
@@ -403,6 +445,13 @@
Log.v(TAG_XML_PARSER, "...automatically generated "
+ canonicalJournalPath + ". Ignore if nonexistent.");
}
+ final String canonicalWalPath =
+ canonicalFile.getCanonicalPath() + "-wal";
+ activeSet.add(canonicalWalPath);
+ if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
+ Log.v(TAG_XML_PARSER, "...automatically generated "
+ + canonicalWalPath + ". Ignore if nonexistent.");
+ }
}
// Special case for sharedpref files (not dirs) also add ".xml" suffix file.
@@ -485,11 +534,19 @@
if ("root".equals(xmlDomain)) {
return FullBackup.ROOT_TREE_TOKEN;
} else if ("file".equals(xmlDomain)) {
- return FullBackup.DATA_TREE_TOKEN;
+ return FullBackup.FILES_TREE_TOKEN;
} else if ("database".equals(xmlDomain)) {
return FullBackup.DATABASE_TREE_TOKEN;
} else if ("sharedpref".equals(xmlDomain)) {
return FullBackup.SHAREDPREFS_TREE_TOKEN;
+ } else if ("device_root".equals(xmlDomain)) {
+ return FullBackup.DEVICE_ROOT_TREE_TOKEN;
+ } else if ("device_file".equals(xmlDomain)) {
+ return FullBackup.DEVICE_FILES_TREE_TOKEN;
+ } else if ("device_database".equals(xmlDomain)) {
+ return FullBackup.DEVICE_DATABASE_TREE_TOKEN;
+ } else if ("device_sharedpref".equals(xmlDomain)) {
+ return FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN;
} else if ("external".equals(xmlDomain)) {
return FullBackup.MANAGED_EXTERNAL_TREE_TOKEN;
} else {
@@ -542,6 +599,14 @@
return ROOT_DIR;
} else if ("sharedpref".equals(domain)) {
return SHAREDPREF_DIR;
+ } else if ("device_file".equals(domain)) {
+ return DEVICE_FILES_DIR;
+ } else if ("device_database".equals(domain)) {
+ return DEVICE_DATABASE_DIR;
+ } else if ("device_root".equals(domain)) {
+ return DEVICE_ROOT_DIR;
+ } else if ("device_sharedpref".equals(domain)) {
+ return DEVICE_SHAREDPREF_DIR;
} else if ("external".equals(domain)) {
return EXTERNAL_DIR;
} else {
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 13aeef0..2e3aca4 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -25,9 +25,15 @@
import android.net.DataUsageRequest;
import android.net.NetworkIdentity;
import android.net.NetworkTemplate;
+import android.net.INetworkStatsService;
+import android.os.Binder;
import android.os.Build;
+import android.os.Message;
+import android.os.Messenger;
import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
/**
@@ -75,16 +81,26 @@
* not included.
*/
public class NetworkStatsManager {
- private final static String TAG = "NetworkStatsManager";
+ private static final String TAG = "NetworkStatsManager";
+ private static final boolean DBG = false;
+
+ /** @hide */
+ public static final int CALLBACK_LIMIT_REACHED = 0;
+ /** @hide */
+ public static final int CALLBACK_RELEASED = 1;
private final Context mContext;
+ private final INetworkStatsService mService;
/**
* {@hide}
*/
public NetworkStatsManager(Context context) {
mContext = context;
+ mService = INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
}
+
/**
* Query network usage statistics summaries. Result is summarised data usage for the whole
* device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This
@@ -322,7 +338,40 @@
checkNotNull(policy, "DataUsagePolicy cannot be null");
checkNotNull(callback, "DataUsageCallback cannot be null");
- // TODO: Implement stub.
+ final Looper looper;
+ if (handler == null) {
+ looper = Looper.myLooper();
+ } else {
+ looper = handler.getLooper();
+ }
+
+ if (DBG) Log.d(TAG, "registerDataUsageCallback called with " + policy);
+
+ NetworkTemplate[] templates;
+ if (policy.subscriberIds == null || policy.subscriberIds.length == 0) {
+ templates = new NetworkTemplate[1];
+ templates[0] = createTemplate(policy.networkType, null /* subscriberId */);
+ } else {
+ templates = new NetworkTemplate[policy.subscriberIds.length];
+ for (int i = 0; i < policy.subscriberIds.length; i++) {
+ templates[i] = createTemplate(policy.networkType, policy.subscriberIds[i]);
+ }
+ }
+ DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET,
+ templates, policy.uids, policy.thresholdInBytes);
+ try {
+ CallbackHandler callbackHandler = new CallbackHandler(looper, callback);
+ callback.request = mService.registerDataUsageCallback(
+ mContext.getOpPackageName(), request, new Messenger(callbackHandler),
+ new Binder());
+ if (DBG) Log.d(TAG, "registerDataUsageCallback returned " + callback.request);
+
+ if (callback.request == null) {
+ Log.e(TAG, "Request from callback is null; should not happen");
+ }
+ } catch (RemoteException e) {
+ if (DBG) Log.d(TAG, "Remote exception when registering callback");
+ }
}
/**
@@ -331,9 +380,15 @@
* @param callback The {@link DataUsageCallback} used when registering.
*/
public void unregisterDataUsageCallback(DataUsageCallback callback) {
- checkNotNull(callback, "DataUsageCallback cannot be null");
-
- // TODO: Implement stub.
+ if (callback == null || callback.request == null
+ || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
+ throw new IllegalArgumentException("Invalid DataUsageCallback");
+ }
+ try {
+ mService.unregisterDataUsageRequest(callback.request);
+ } catch (RemoteException e) {
+ if (DBG) Log.d(TAG, "Remote exception when unregistering callback");
+ }
}
/**
@@ -366,4 +421,38 @@
}
return template;
}
+
+ private static class CallbackHandler extends Handler {
+ private DataUsageCallback mCallback;
+ CallbackHandler(Looper looper, DataUsageCallback callback) {
+ super(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ DataUsageRequest request =
+ (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY);
+
+ switch (message.what) {
+ case CALLBACK_LIMIT_REACHED: {
+ if (mCallback != null) {
+ mCallback.onLimitReached();
+ } else {
+ Log.e(TAG, "limit reached with released callback for " + request);
+ }
+ break;
+ }
+ case CALLBACK_RELEASED: {
+ if (DBG) Log.d(TAG, "callback released for " + request);
+ mCallback = null;
+ break;
+ }
+ }
+ }
+
+ private static Object getObject(Message msg, String key) {
+ return msg.getData().getParcelable(key);
+ }
+ }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fff0c14..0cdbef0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -811,6 +811,25 @@
public abstract File getSharedPreferencesPath(String name);
/**
+ * Returns the absolute path to the directory on the filesystem where all
+ * private files belonging to this app are stored. This is the top-level
+ * directory under which {@link #getFilesDir()}, {@link #getCacheDir()}, etc
+ * are contained. Apps should <em>not</em> create any files or directories
+ * as direct children of this directory, since it's a reserved namespace
+ * belonging to the platform. Instead, use {@link #getDir(String, int)} or
+ * other storage APIs.
+ * <p>
+ * The returned path may change over time if the calling app is moved to an
+ * adopted storage device, so only relative paths should be persisted.
+ * <p>
+ * No additional permissions are required for the calling app to read or
+ * write files under the returned path.
+ *
+ * @see #getDir(String, int)
+ */
+ public abstract File getDataDir();
+
+ /**
* Returns the absolute path to the directory on the filesystem where files
* created with {@link #openFileOutput} are stored.
* <p>
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 61b87a9..323c9bf 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -212,6 +212,11 @@
}
@Override
+ public File getDataDir() {
+ return mBase.getDataDir();
+ }
+
+ @Override
public File getFilesDir() {
return mBase.getFilesDir();
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9082482..ad174f6 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -523,6 +523,14 @@
public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES = 1 << 11;
/**
+ * Value for {@link #privateFlags}: {@code true} means the OS should go ahead and
+ * run full-data backup operations for the app even when it is in a
+ * foreground-equivalent run state. Defaults to {@code false} if unspecified.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 12;
+
+ /**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* {@hide}
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0967608..188e1d7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3175,7 +3175,7 @@
*/
public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
if (ArrayUtils.isEmpty(permissions)) {
- throw new NullPointerException("permission cannot be null or empty");
+ throw new IllegalArgumentException("permission cannot be null or empty");
}
Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 8bf20bf..7fe7f84 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -59,12 +59,6 @@
public abstract void setLocationPackagesProvider(PackagesProvider provider);
/**
- * Sets the input method packages provider.
- * @param provider The packages provider.
- */
- public abstract void setImePackagesProvider(PackagesProvider provider);
-
- /**
* Sets the voice interaction packages provider.
* @param provider The packages provider.
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f6ae020..ce6ddfd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2669,8 +2669,9 @@
if (allowBackup) {
ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
- // backupAgent, killAfterRestore, fullBackupContent and restoreAnyVersion are only
- // relevant if backup is possible for the given application.
+ // backupAgent, killAfterRestore, fullBackupContent, backupInForeground,
+ // and restoreAnyVersion are only relevant if backup is possible for the
+ // given application.
String backupAgent = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
Configuration.NATIVE_CONFIG_VERSION);
@@ -2696,6 +2697,11 @@
false)) {
ai.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_backupInForeground,
+ false)) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
+ }
}
TypedValue v = sa.peekValue(
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index aa697ea..13ba6cc 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -211,6 +211,9 @@
public int dozeScreenBrightness;
public int dozeScreenState;
+ // If true, use twilight to affect the brightness.
+ public boolean useTwilight;
+
public DisplayPowerRequest() {
policy = POLICY_BRIGHT;
useProximitySensor = false;
@@ -242,6 +245,7 @@
boostScreenBrightness = other.boostScreenBrightness;
dozeScreenBrightness = other.dozeScreenBrightness;
dozeScreenState = other.dozeScreenState;
+ useTwilight = other.useTwilight;
}
@Override
@@ -262,7 +266,8 @@
&& lowPowerMode == other.lowPowerMode
&& boostScreenBrightness == other.boostScreenBrightness
&& dozeScreenBrightness == other.dozeScreenBrightness
- && dozeScreenState == other.dozeScreenState;
+ && dozeScreenState == other.dozeScreenState
+ && useTwilight == other.useTwilight;
}
@Override
@@ -282,7 +287,8 @@
+ ", lowPowerMode=" + lowPowerMode
+ ", boostScreenBrightness=" + boostScreenBrightness
+ ", dozeScreenBrightness=" + dozeScreenBrightness
- + ", dozeScreenState=" + Display.stateToString(dozeScreenState);
+ + ", dozeScreenState=" + Display.stateToString(dozeScreenState)
+ + ", useTwilight=" + useTwilight;
}
public static String policyToString(int policy) {
diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java
index 0e46f4c..5e96cc1 100644
--- a/core/java/android/net/DataUsageRequest.java
+++ b/core/java/android/net/DataUsageRequest.java
@@ -34,6 +34,11 @@
/**
* @hide
*/
+ public static final String PARCELABLE_KEY = "DataUsageRequest";
+
+ /**
+ * @hide
+ */
public static final int REQUEST_ID_UNSET = 0;
/**
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 6436e42..2eea940 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -16,10 +16,13 @@
package android.net;
+import android.net.DataUsageRequest;
import android.net.INetworkStatsSession;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
+import android.os.IBinder;
+import android.os.Messenger;
/** {@hide} */
interface INetworkStatsService {
@@ -57,4 +60,11 @@
/** Advise persistance threshold; may be overridden internally. */
void advisePersistThreshold(long thresholdBytes);
+ /** Registers a callback on data usage. */
+ DataUsageRequest registerDataUsageCallback(String callingPackage,
+ in DataUsageRequest request, in Messenger messenger, in IBinder binder);
+
+ /** Unregisters a callback on data usage. */
+ void unregisterDataUsageRequest(in DataUsageRequest request);
+
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 4487cab..c6d919f 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -57,90 +57,6 @@
public native static int resetConnections(String interfaceName, int mask);
/**
- * Start the DHCP client daemon, in order to have it request addresses
- * for the named interface. This returns {@code true} if the DHCPv4 daemon
- * starts, {@code false} otherwise. This call blocks until such time as a
- * result is available or the default discovery timeout has been reached.
- * Callers should check {@link #getDhcpResults} to determine whether DHCP
- * succeeded or failed, and if it succeeded, to fetch the {@link DhcpResults}.
- * @param interfaceName the name of the interface to configure
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean startDhcp(String interfaceName);
-
- /**
- * Initiate renewal on the DHCP client daemon for the named interface. This
- * returns {@code true} if the DHCPv4 daemon has been notified, {@code false}
- * otherwise. This call blocks until such time as a result is available or
- * the default renew timeout has been reached. Callers should check
- * {@link #getDhcpResults} to determine whether DHCP succeeded or failed,
- * and if it succeeded, to fetch the {@link DhcpResults}.
- * @param interfaceName the name of the interface to configure
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean startDhcpRenew(String interfaceName);
-
- /**
- * Start the DHCP client daemon, in order to have it request addresses
- * for the named interface, and then configure the interface with those
- * addresses. This call blocks until it obtains a result (either success
- * or failure) from the daemon.
- * @param interfaceName the name of the interface to configure
- * @param dhcpResults if the request succeeds, this object is filled in with
- * the IP address information.
- * @return {@code true} for success, {@code false} for failure
- */
- public static boolean runDhcp(String interfaceName, DhcpResults dhcpResults) {
- return startDhcp(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
- }
-
- /**
- * Initiate renewal on the DHCP client daemon. This call blocks until it obtains
- * a result (either success or failure) from the daemon.
- * @param interfaceName the name of the interface to configure
- * @param dhcpResults if the request succeeds, this object is filled in with
- * the IP address information.
- * @return {@code true} for success, {@code false} for failure
- */
- public static boolean runDhcpRenew(String interfaceName, DhcpResults dhcpResults) {
- return startDhcpRenew(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
- }
-
- /**
- * Fetch results from the DHCP client daemon. This call returns {@code true} if
- * if there are results available to be read, {@code false} otherwise.
- * @param interfaceName the name of the interface to configure
- * @param dhcpResults if the request succeeds, this object is filled in with
- * the IP address information.
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean getDhcpResults(String interfaceName, DhcpResults dhcpResults);
-
- /**
- * Shut down the DHCP client daemon.
- * @param interfaceName the name of the interface for which the daemon
- * should be stopped
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean stopDhcp(String interfaceName);
-
- /**
- * Release the current DHCP lease.
- * @param interfaceName the name of the interface for which the lease should
- * be released
- * @return {@code true} for success, {@code false} for failure
- */
- public native static boolean releaseDhcpLease(String interfaceName);
-
- /**
- * Return the last DHCP-related error message that was recorded.
- * <p/>NOTE: This string is not localized, but currently it is only
- * used in logging.
- * @return the most recent error message, if any
- */
- public native static String getDhcpError();
-
- /**
* Attaches a socket filter that accepts DHCP packets to the given socket.
*/
public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b33e807..a738b2e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2827,7 +2827,7 @@
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
dumpLine(pw, 0 /* uid */, category, GLOBAL_WIFI_DATA, wifiOnTime / 1000,
- wifiRunningTime / 1000, /* legacy fields follow, keep at 0 */ 0, 0, 0, 0);
+ wifiRunningTime / 1000, /* legacy fields follow, keep at 0 */ 0, 0, 0);
dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_WIFI_CONTROLLER_DATA,
getWifiControllerActivity(), which);
diff --git a/core/java/android/os/CpuUsageInfo.aidl b/core/java/android/os/CpuUsageInfo.aidl
new file mode 100644
index 0000000..f81aefe
--- /dev/null
+++ b/core/java/android/os/CpuUsageInfo.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+parcelable CpuUsageInfo;
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index c2aca41..1b79497 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -307,7 +307,11 @@
}
}
- /**
+ public static void stringToFile(File file, String string) throws IOException {
+ stringToFile(file.getAbsolutePath(), string);
+ }
+
+ /**
* Writes string to file. Basically same as "echo -n $string > $filename"
*
* @param filename
diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java
index bc317b6..c72a6481 100644
--- a/core/java/android/os/HardwarePropertiesManager.java
+++ b/core/java/android/os/HardwarePropertiesManager.java
@@ -17,10 +17,12 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.content.Context;
+import android.util.Log;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-
/**
* The HardwarePropertiesManager class provides a mechanism of accessing hardware state of a
* device: CPU, GPU and battery temperatures, CPU usage per core, fan speed, etc.
@@ -29,11 +31,7 @@
private static final String TAG = HardwarePropertiesManager.class.getSimpleName();
- private static native void nativeInit();
-
- private static native float[] nativeGetFanSpeeds();
- private static native float[] nativeGetDeviceTemperatures(int type);
- private static native CpuUsageInfo[] nativeGetCpuUsages();
+ private final IHardwarePropertiesManager mService;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@@ -54,9 +52,13 @@
/** Temperature of battery in Celsius. */
public static final int DEVICE_TEMPERATURE_BATTERY = 2;
+ /** Calling app context. */
+ private final Context mContext;
+
/** @hide */
- public HardwarePropertiesManager() {
- nativeInit();
+ public HardwarePropertiesManager(Context context, IHardwarePropertiesManager service) {
+ mContext = context;
+ mService = service;
}
/**
@@ -68,13 +70,19 @@
* Empty if platform doesn't provide the queried temperature.
*
* @throws IllegalArgumentException if an incorrect temperature type is queried.
+ * @throws SecurityException if a non profile or device owner tries to call this method.
*/
public @NonNull float[] getDeviceTemperatures(@DeviceTemperatureType int type) {
switch (type) {
case DEVICE_TEMPERATURE_CPU:
case DEVICE_TEMPERATURE_GPU:
case DEVICE_TEMPERATURE_BATTERY:
- return nativeGetDeviceTemperatures(type);
+ try {
+ return mService.getDeviceTemperatures(mContext.getOpPackageName(), type);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not get device temperatures", e);
+ return new float[0];
+ }
default:
throw new IllegalArgumentException();
}
@@ -85,18 +93,32 @@
*
* @return an array of {@link android.os.CpuUsageInfo} for each core.
* Empty if CPU usage is not supported on this system.
+ *
+ * @throws SecurityException if a non profile or device owner tries to call this method.
*/
public @NonNull CpuUsageInfo[] getCpuUsages() {
- return nativeGetCpuUsages();
+ try {
+ return mService.getCpuUsages(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not get CPU usages", e);
+ return new CpuUsageInfo[0];
+ }
}
/**
* Return an array of fan speeds in RPM.
*
- * @return an arrat of float fan speeds. Empty if there is no fans or fan speed
- * not supported on this system.
+ * @return an array of float fan speeds in RPM. Empty if there are no fans or fan speed is not
+ * supported on this system.
+ *
+ * @throws SecurityException if a non profile or device owner tries to call this method.
*/
public @NonNull float[] getFanSpeeds() {
- return nativeGetFanSpeeds();
+ try {
+ return mService.getFanSpeeds(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not get fan speeds", e);
+ return new float[0];
+ }
}
}
diff --git a/core/java/android/os/IHardwarePropertiesManager.aidl b/core/java/android/os/IHardwarePropertiesManager.aidl
new file mode 100644
index 0000000..bcf0dc8
--- /dev/null
+++ b/core/java/android/os/IHardwarePropertiesManager.aidl
@@ -0,0 +1,28 @@
+/*
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+import android.os.CpuUsageInfo;
+
+/** @hide */
+
+interface IHardwarePropertiesManager {
+ float[] getDeviceTemperatures(String callingPackage, int type);
+ CpuUsageInfo[] getCpuUsages(String callingPackage);
+ float[] getFanSpeeds(String callingPackage);
+}
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index 4d3bea44..ed7c7c5 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -311,7 +311,7 @@
*/
public final long untilTimestampMillis;
- BlockSuppressalStatus(boolean isSuppressed, long untilTimestampMillis) {
+ public BlockSuppressalStatus(boolean isSuppressed, long untilTimestampMillis) {
this.isSuppressed = isSuppressed;
this.untilTimestampMillis = untilTimestampMillis;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5ab2b00..770cde7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -114,6 +114,21 @@
"android.settings.LOCATION_SOURCE_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of users.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_USER_SETTINGS =
+ "android.settings.USER_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of wireless controls
* such as Wi-Fi, Bluetooth and Mobile networks.
* <p>
@@ -1218,6 +1233,8 @@
* Input: Nothing.
* <p>
* Output: Nothing.
+ *
+ * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS
@@ -5922,6 +5939,52 @@
"camera_double_tap_power_gesture_disabled";
/**
+
+ /**
+ * Behavior of twilight on the device.
+ * One of {@link #TWILIGHT_MODE_LOCKED_OFF}, {@link #TWILIGHT_MODE_LOCKED_ON}
+ * or {@link #TWILIGHT_MODE_AUTO}.
+ * @hide
+ */
+ public static final String TWILIGHT_MODE = "twilight_mode";
+
+ /**
+ * Twilight mode always off.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_LOCKED_OFF = 0;
+
+ /**
+ * Twilight mode always on.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_LOCKED_ON = 1;
+
+ /**
+ * Twilight mode auto.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_AUTO = 2;
+
+ /**
+ * Twilight mode auto, temporarily overriden to on.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_AUTO_OVERRIDE_OFF = 3;
+
+ /**
+ * Twilight mode auto, temporarily overriden to off.
+ * @hide
+ */
+ public static final int TWILIGHT_MODE_AUTO_OVERRIDE_ON = 4;
+
+ /**
+ * Whether brightness should automatically adjust based on twilight state.
+ * @hide
+ */
+ public static final String BRIGHTNESS_USE_TWILIGHT = "brightness_use_twilight";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -6295,6 +6358,18 @@
public static final String BLUETOOTH_DISABLED_PROFILES = "bluetooth_disabled_profiles";
/**
+ * A semi-colon separated list of Bluetooth interoperability workarounds.
+ * Each entry is a partial Bluetooth device address string and an integer representing
+ * the feature to be disabled, separated by a comma. The integer must correspond
+ * to a interoperability feature as defined in "interop.h" in /system/bt.
+ * <p>
+ * Example: <br/>
+ * "00:11:22,0;01:02:03:04,2"
+ * @hide
+ */
+ public static final String BLUETOOTH_INTEROPERABILITY_LIST = "bluetooth_interoperability_list";
+
+ /**
* The policy for deciding when Wi-Fi should go to sleep (which will in
* turn switch to using the mobile data as an Internet connection).
* <p>
@@ -6964,6 +7039,12 @@
*/
public static final String WEBVIEW_PROVIDER = "webview_provider";
+ /**
+ * Developer setting to enable WebView multiprocess rendering.
+ * @hide
+ */
+ public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
+
/**
* Whether Wifi display is enabled/disabled
* 0=disabled. 1=enabled.
@@ -7763,13 +7844,20 @@
public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
/**
- * If 1, the activity manager will aggressively finish activities and
+ * If not 0, the activity manager will aggressively finish activities and
* processes as soon as they are no longer needed. If 0, the normal
* extended lifetime is used.
*/
public static final String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
/**
+ * @hide
+ * If not 0, the activity manager will implement a looser version of background
+ * check that is more compatible with existing apps.
+ */
+ public static final String LENIENT_BACKGROUND_CHECK = "lenient_background_check";
+
+ /**
* Use Dock audio output for media:
* 0 = disabled
* 1 = enabled
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index e01f2a0..eb3d031 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -72,6 +72,7 @@
public static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503;
public static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
public static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
+ public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index fb58f4e..b5387f1 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -97,14 +97,11 @@
/** Notification was canceled because it was an invisible member of a group. */
public static final int REASON_GROUP_OPTIMIZATION = 13;
- /** Notification was canceled by the user banning the topic. */
- public static final int REASON_TOPIC_BANNED = 14;
-
/** Notification was canceled by the device administrator suspending the package. */
- public static final int REASON_PACKAGE_SUSPENDED = 15;
+ public static final int REASON_PACKAGE_SUSPENDED = 14;
/** Notification was canceled by the owning managed profile being turned off. */
- public static final int REASON_PROFILE_TURNED_OFF = 16;
+ public static final int REASON_PROFILE_TURNED_OFF = 15;
public class Adjustment {
int mImportance;
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 0cf1175..553d539 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -16,6 +16,8 @@
package android.service.quicksettings;
import android.Manifest;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.app.Dialog;
import android.app.Service;
@@ -74,6 +76,14 @@
public class TileService extends Service {
/**
+ * An activity that provides a user interface for adjusting TileService preferences.
+ * Optional but recommended for apps that implement a TileService.
+ */
+ @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+ public static final String ACTION_QS_TILE_PREFERENCES
+ = "android.service.quicksettings.action.QS_TILE_PREFERENCES";
+
+ /**
* Action that identifies a Service as being a TileService.
*/
public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
diff --git a/core/java/android/text/style/ReplacementSpan.java b/core/java/android/text/style/ReplacementSpan.java
index 26c725f..07190b2 100644
--- a/core/java/android/text/style/ReplacementSpan.java
+++ b/core/java/android/text/style/ReplacementSpan.java
@@ -16,18 +16,49 @@
package android.text.style;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Paint;
import android.graphics.Canvas;
import android.text.TextPaint;
public abstract class ReplacementSpan extends MetricAffectingSpan {
- public abstract int getSize(Paint paint, CharSequence text,
- int start, int end,
- Paint.FontMetricsInt fm);
- public abstract void draw(Canvas canvas, CharSequence text,
- int start, int end, float x,
- int top, int y, int bottom, Paint paint);
+ /**
+ * Returns the width of the span. Extending classes can set the height of the span by updating
+ * attributes of {@link android.graphics.Paint.FontMetricsInt}. If the span covers the whole
+ * text, and the height is not set,
+ * {@link #draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)} will not be
+ * called for the span.
+ *
+ * @param paint Paint instance.
+ * @param text Current text.
+ * @param start Start character index for span.
+ * @param end End character index for span.
+ * @param fm Font metrics, can be null.
+ * @return Width of the span.
+ */
+ public abstract int getSize(@NonNull Paint paint, CharSequence text,
+ @IntRange(from = 0) int start, @IntRange(from = 0) int end,
+ @Nullable Paint.FontMetricsInt fm);
+
+ /**
+ * Draws the span into the canvas.
+ *
+ * @param canvas Canvas into which the span should be rendered.
+ * @param text Current text.
+ * @param start Start character index for span.
+ * @param end End character index for span.
+ * @param x Edge of the replacement closest to the leading margin.
+ * @param top Top of the line.
+ * @param y Baseline.
+ * @param bottom Bottom of the line.
+ * @param paint Paint instance.
+ */
+ public abstract void draw(@NonNull Canvas canvas, CharSequence text,
+ @IntRange(from = 0) int start, @IntRange(from = 0) int end, float x,
+ int top, int y, int bottom, @NonNull Paint paint);
/**
* This method does nothing, since ReplacementSpans are measured
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 544444d..3d7cb49 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -377,8 +377,9 @@
* Helper function for long messages. Uses the LineBreakBufferedWriter to break
* up long messages and stacktraces along newlines, but tries to write in large
* chunks. This is to avoid truncation.
+ * @hide
*/
- private static int printlns(int bufID, int priority, String tag, String msg,
+ public static int printlns(int bufID, int priority, String tag, String msg,
Throwable tr) {
ImmediateLogWriter logWriter = new ImmediateLogWriter(bufID, priority, tag);
// Acceptable buffer size. Get the native buffer size, subtract two zero terminators,
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 664c02a..c7b1d03 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -1053,6 +1053,7 @@
private void prefetchPredecessorsOfVirtualNode(AccessibilityNodeInfo root,
View providerHost, AccessibilityNodeProvider provider,
List<AccessibilityNodeInfo> outInfos) {
+ final int initialResultSize = outInfos.size();
long parentNodeId = root.getParentNodeId();
int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
@@ -1071,6 +1072,12 @@
AccessibilityNodeProvider.HOST_VIEW_ID);
}
if (parent == null) {
+ // Going up the parent relation we found a null predecessor,
+ // so remove these disconnected nodes form the result.
+ final int currentResultSize = outInfos.size();
+ for (int i = currentResultSize - 1; i >= initialResultSize; i--) {
+ outInfos.remove(i);
+ }
// Couldn't obtain the parent, which means we have a
// disconnected sub-tree. Abort prefetch immediately.
return;
diff --git a/core/java/android/view/IDockedStackListener.aidl b/core/java/android/view/IDockedStackListener.aidl
index 77fa7e2..cbc8dbd 100644
--- a/core/java/android/view/IDockedStackListener.aidl
+++ b/core/java/android/view/IDockedStackListener.aidl
@@ -33,4 +33,13 @@
* Called when the docked stack gets created or removed.
*/
void onDockedStackExistsChanged(boolean exists);
+
+ /**
+ * Called when window manager decides to minimize the docked stack. The divider should make
+ * itself not interactable and shrink a bit in this state.
+ *
+ * @param minimized Whether the docked stack is currently minimized.
+ * @param animDuration The duration of the animation for changing the minimized state.
+ */
+ void onDockedStackMinimizedChanged(boolean minimized, long animDuration);
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index ca41d78..c972476 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -380,7 +380,7 @@
void destroy() {
mInitialized = false;
updateEnabledState(null);
- nDestroy(mNativeProxy);
+ nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
}
/**
@@ -994,7 +994,7 @@
float lightX, float lightY, float lightZ);
private static native void nSetOpaque(long nativeProxy, boolean opaque);
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
- private static native void nDestroy(long nativeProxy);
+ private static native void nDestroy(long nativeProxy, long rootRenderNode);
private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9e9ad67..70a0e01 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -21584,7 +21584,7 @@
*/
public void setPointerIcon(PointerIcon pointerIcon) {
mPointerIcon = pointerIcon;
- if (mAttachInfo == null) {
+ if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) {
return;
}
try {
@@ -22637,6 +22637,11 @@
boolean mHighContrastText;
/**
+ * Set to true if a pointer event is currently being handled.
+ */
+ boolean mHandlingPointerEvent;
+
+ /**
* Global to the view hierarchy used as a temporary for dealing with
* x/y points in the transparent region computations.
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6dc5ccc..0517788 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4311,6 +4311,24 @@
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
+ mAttachInfo.mUnbufferedDispatchRequested = false;
+ final View eventTarget =
+ (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
+ mCapturingView : mView;
+ mAttachInfo.mHandlingPointerEvent = true;
+ boolean handled = eventTarget.dispatchPointerEvent(event);
+ maybeUpdatePointerIcon(event);
+ mAttachInfo.mHandlingPointerEvent = false;
+ if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
+ mUnbufferedInputDispatch = true;
+ if (mConsumeBatchedInputScheduled) {
+ scheduleConsumeBatchedInputImmediately();
+ }
+ }
+ return handled ? FINISH_HANDLED : FORWARD;
+ }
+
+ private void maybeUpdatePointerIcon(MotionEvent event) {
if (event.getPointerCount() == 1
&& event.isFromSource(InputDevice.SOURCE_MOUSE)) {
if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
@@ -4327,19 +4345,6 @@
}
}
}
-
- mAttachInfo.mUnbufferedDispatchRequested = false;
- final View eventTarget =
- (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
- mCapturingView : mView;
- boolean handled = eventTarget.dispatchPointerEvent(event);
- if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
- mUnbufferedInputDispatch = true;
- if (mConsumeBatchedInputScheduled) {
- scheduleConsumeBatchedInputImmediately();
- }
- }
- return handled ? FINISH_HANDLED : FORWARD;
}
private int processTrackballEvent(QueuedInputEvent q) {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 609c471..a8b7a7b 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -631,7 +631,7 @@
/**
* Return the display width available after excluding any screen
- * decorations that can never be removed. That is, system bar or
+ * decorations that could never be removed in Honeycomb. That is, system bar or
* button bar.
*/
public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation,
@@ -639,7 +639,7 @@
/**
* Return the display height available after excluding any screen
- * decorations that can never be removed. That is, system bar or
+ * decorations that could never be removed in Honeycomb. That is, system bar or
* button bar.
*/
public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation,
@@ -1350,4 +1350,16 @@
*/
public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
Rect outInsets);
+
+ /**
+ * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
+ * bar or button bar. See {@link #getNonDecorDisplayWidth}.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param outInsets the insets to return
+ */
+ public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
+ Rect outInsets);
}
diff --git a/core/java/android/view/animation/ClipRectTBAnimation.java b/core/java/android/view/animation/ClipRectTBAnimation.java
deleted file mode 100644
index 06f86ce..0000000
--- a/core/java/android/view/animation/ClipRectTBAnimation.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.animation;
-
-import android.graphics.Rect;
-
-/**
- * Special case of ClipRectAnimation that animates only the top/bottom
- * dimensions of the clip, picking up the other dimensions from whatever is
- * set on the transform already.
- *
- * @hide
- */
-public class ClipRectTBAnimation extends ClipRectAnimation {
-
- /**
- * Constructor. Passes in 0 for Left/Right parameters of ClipRectAnimation
- */
- public ClipRectTBAnimation(int fromT, int fromB, int toT, int toB) {
- super(0, fromT, 0, fromB, 0, toT, 0, toB);
- }
-
- /**
- * Calculates and sets clip rect on given transformation. It uses existing values
- * on the Transformation for Left/Right clip parameters.
- */
- @Override
- protected void applyTransformation(float it, Transformation tr) {
- Rect oldClipRect = tr.getClipRect();
- tr.setClipRect(oldClipRect.left, mFromRect.top + (int) ((mToRect.top - mFromRect.top) * it),
- oldClipRect.right,
- mFromRect.bottom + (int) ((mToRect.bottom - mFromRect.bottom) * it));
- }
-
-}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index a10f792..6a830f8 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
+import android.os.Handler;
import android.os.SystemClock;
import android.text.Editable;
import android.text.NoCopySpan;
@@ -602,6 +603,10 @@
return false;
}
+ public Handler getHandler() {
+ return null;
+ }
+
/**
* The default implementation places the given text into the editable,
* replacing any existing composing text. The new text is marked as
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index eb773e2..2a9706d 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -17,6 +17,7 @@
package android.view.inputmethod;
import android.os.Bundle;
+import android.os.Handler;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -786,4 +787,15 @@
* {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}.
*/
public boolean requestCursorUpdates(int cursorUpdateMode);
+
+ /**
+ * Called by the {@link InputMethodManager} to enable application developers to specify a
+ * dedicated {@link Handler} on which incoming IPC method calls from input methods will be
+ * dispatched.
+ *
+ * <p>Note: This does nothing when called from input methods.</p>
+ *
+ * @return {@code null} to use the default {@link Handler}.
+ */
+ public Handler getHandler();
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index e5ae422..65c7654 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -17,6 +17,7 @@
package android.view.inputmethod;
import android.os.Bundle;
+import android.os.Handler;
import android.view.KeyEvent;
/**
@@ -133,4 +134,8 @@
public boolean requestCursorUpdates(int cursorUpdateMode) {
return mTarget.requestCursorUpdates(cursorUpdateMode);
}
+
+ public Handler getHandler() {
+ return mTarget.getHandler();
+ }
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index d97f8af..281babe 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -428,18 +428,6 @@
}
}
- /**
- * @return {@code true} if the {@link android.inputmethodservice.InputMethodService} is marked
- * to be Encryption-Aware.
- * @hide
- */
- public boolean isEncryptionAware() {
- if (mService == null || mService.serviceInfo == null) {
- return false;
- }
- return mService.serviceInfo.encryptionAware;
- }
-
public void dump(Printer pw, String prefix) {
pw.println(prefix + "mId=" + mId
+ " mSettingsActivityName=" + mSettingsActivityName
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0ed2299..2de9897 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1215,7 +1215,7 @@
if (mCurrentTextBoxAttribute == null) {
controlFlags |= CONTROL_START_INITIAL;
}
-
+
// Hook 'em up and let 'er rip.
mCurrentTextBoxAttribute = tba;
mServedConnecting = false;
@@ -1230,7 +1230,9 @@
mCursorCandEnd = -1;
mCursorRect.setEmpty();
mCursorAnchorInfo = null;
- servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic, this);
+ final Handler icHandler = ic.getHandler();
+ servedContext = new ControlledInputConnectionWrapper(
+ icHandler != null ? icHandler.getLooper() : vh.getLooper(), ic, this);
} else {
servedContext = null;
}
@@ -1238,7 +1240,7 @@
mServedInputConnectionWrapper.deactivate();
}
mServedInputConnectionWrapper = servedContext;
-
+
try {
if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
+ ic + " tba=" + tba + " controlFlags=#"
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 0f58ba3..647d4dc 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -39,6 +39,7 @@
import android.security.KeyChain;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -2528,6 +2529,11 @@
}
@Override
+ public boolean onDragEvent(DragEvent event) {
+ return mProvider.getViewDelegate().onDragEvent(event);
+ }
+
+ @Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
// This method may be called in the constructor chain, before the WebView provider is
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 3ce034c..94d231c 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -30,6 +30,7 @@
import android.os.Bundle;
import android.os.Message;
import android.print.PrintDocumentAdapter;
+import android.view.DragEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -334,6 +335,8 @@
public InputConnection onCreateInputConnection(EditorInfo outAttrs);
+ public boolean onDragEvent(DragEvent event);
+
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event);
public boolean onKeyDown(int keyCode, KeyEvent event);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index b689564..496f7ee 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -28,6 +28,7 @@
import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.os.Debug;
+import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.StrictMode;
@@ -5930,6 +5931,11 @@
public boolean requestCursorUpdates(int cursorUpdateMode) {
return getTarget().requestCursorUpdates(cursorUpdateMode);
}
+
+ @Override
+ public Handler getHandler() {
+ return getTarget().getHandler();
+ }
}
/**
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 8c3c2b5..6085164 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -311,24 +311,6 @@
}
@Override
- public boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
- final Intent intent = target.getResolvedIntent();
- final ResolveInfo resolve = target.getResolveInfo();
-
- // When GET_CONTENT is handled by the DocumentsUI system component,
- // we're okay automatically launching it, since it offers it's own
- // intent disambiguation UI.
- if (intent != null && Intent.ACTION_GET_CONTENT.equals(intent.getAction())
- && resolve != null && resolve.priority > 0
- && resolve.activityInfo != null && DocumentsContract.PACKAGE_DOCUMENTS_UI
- .equals(resolve.activityInfo.packageName)) {
- return true;
- }
-
- return false;
- }
-
- @Override
public void showTargetDetails(ResolveInfo ri) {
ComponentName name = ri.activityInfo.getComponentName();
boolean pinned = mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 9fa2c23..b13be97 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -44,6 +44,7 @@
int checkAudioOperation(int code, int usage, int uid, String packageName);
void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
- void setUserRestrictions(in Bundle restrictions, int userHandle);
+ void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
+ void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle);
void removeUser(int userHandle);
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 3b8b7cb..e298201 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -57,8 +57,7 @@
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
private static int Clog_e(String tag, String msg, Throwable tr) {
- return Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag,
- msg + '\n' + Log.getStackTraceString(tr));
+ return Log.printlns(Log.LOG_ID_CRASH, Log.ERROR, tag, msg, tr);
}
/**
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index af3f7ec..3d60926 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -198,7 +198,7 @@
int mStackId;
private boolean mWindowResizeCallbacksAdded = false;
-
+ private Drawable.Callback mLastBackgroundDrawableCb = null;
private BackdropFrameRenderer mBackdropFrameRenderer = null;
private Drawable mResizingBackgroundDrawable;
private Drawable mCaptionBackgroundDrawable;
@@ -863,6 +863,7 @@
if (getBackground() != drawable) {
setBackgroundDrawable(drawable);
if (drawable != null) {
+ mResizingBackgroundDrawable = drawable;
drawable.getPadding(mBackgroundPadding);
} else {
mBackgroundPadding.setEmpty();
@@ -1913,6 +1914,11 @@
final ThreadedRenderer renderer = getHardwareRenderer();
if (renderer != null) {
loadBackgroundDrawablesIfNeeded();
+ if (mResizingBackgroundDrawable != null) {
+ mLastBackgroundDrawableCb = mResizingBackgroundDrawable.getCallback();
+ mResizingBackgroundDrawable.setCallback(null);
+ }
+
mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
@@ -1956,6 +1962,11 @@
/** Release the renderer thread which is usually done when the user stops resizing. */
private void releaseThreadedRenderer() {
+ if (mResizingBackgroundDrawable != null && mLastBackgroundDrawableCb != null) {
+ mResizingBackgroundDrawable.setCallback(mLastBackgroundDrawableCb);
+ mLastBackgroundDrawableCb = null;
+ }
+
if (mBackdropFrameRenderer != null) {
mBackdropFrameRenderer.releaseRenderer();
mBackdropFrameRenderer = null;
diff --git a/core/java/com/android/internal/policy/DockedDividerUtils.java b/core/java/com/android/internal/policy/DockedDividerUtils.java
index 00c65bd..c68e506 100644
--- a/core/java/com/android/internal/policy/DockedDividerUtils.java
+++ b/core/java/com/android/internal/policy/DockedDividerUtils.java
@@ -17,9 +17,9 @@
package com.android.internal.policy;
import android.graphics.Rect;
-import android.view.WindowManager;
import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
@@ -35,46 +35,61 @@
int displayWidth, int displayHeight, int dividerSize) {
outRect.set(0, 0, displayWidth, displayHeight);
switch (dockSide) {
- case WindowManager.DOCKED_LEFT:
+ case DOCKED_LEFT:
outRect.right = position;
break;
- case WindowManager.DOCKED_TOP:
+ case DOCKED_TOP:
outRect.bottom = position;
break;
- case WindowManager.DOCKED_RIGHT:
+ case DOCKED_RIGHT:
outRect.left = position + dividerSize;
break;
- case WindowManager.DOCKED_BOTTOM:
+ case DOCKED_BOTTOM:
outRect.top = position + dividerSize;
break;
}
- sanitizeStackBounds(outRect);
+ sanitizeStackBounds(outRect, dockSide == DOCKED_LEFT || dockSide == DOCKED_TOP);
}
- public static void sanitizeStackBounds(Rect bounds) {
- if (bounds.left >= bounds.right) {
- bounds.left = bounds.right - 1;
- }
- if (bounds.top >= bounds.bottom) {
- bounds.top = bounds.bottom - 1;
- }
- if (bounds.right <= bounds.left) {
- bounds.right = bounds.left + 1;
- }
- if (bounds.bottom <= bounds.top) {
- bounds.bottom = bounds.top + 1;
+ /**
+ * Makes sure that the bounds are always valid, i. e. they are at least one pixel high and wide.
+ *
+ * @param bounds The bounds to sanitize.
+ * @param topLeft Pass true if the bounds are at the top/left of the screen, false if they are
+ * at the bottom/right. This is used to determine in which direction to extend
+ * the bounds.
+ */
+ public static void sanitizeStackBounds(Rect bounds, boolean topLeft) {
+
+ // If the bounds are either on the top or left of the screen, rather move it further to the
+ // left/top to make it more offscreen. If they are on the bottom or right, push them off the
+ // screen by moving it even more to the bottom/right.
+ if (topLeft) {
+ if (bounds.left >= bounds.right) {
+ bounds.left = bounds.right - 1;
+ }
+ if (bounds.top >= bounds.bottom) {
+ bounds.top = bounds.bottom - 1;
+ }
+ } else {
+ if (bounds.right <= bounds.left) {
+ bounds.right = bounds.left + 1;
+ }
+ if (bounds.bottom <= bounds.top) {
+ bounds.bottom = bounds.top + 1;
+ }
}
}
public static int calculatePositionForBounds(Rect bounds, int dockSide, int dividerSize) {
switch (dockSide) {
- case WindowManager.DOCKED_LEFT:
+ case DOCKED_LEFT:
return bounds.right;
- case WindowManager.DOCKED_TOP:
+ case DOCKED_TOP:
return bounds.bottom;
- case WindowManager.DOCKED_RIGHT:
+ case DOCKED_RIGHT:
return bounds.left - dividerSize;
- case WindowManager.DOCKED_BOTTOM:
+ case DOCKED_BOTTOM:
return bounds.top - dividerSize;
default:
return 0;
@@ -109,16 +124,16 @@
public static int invertDockSide(int dockSide) {
switch (dockSide) {
- case WindowManager.DOCKED_LEFT:
- return WindowManager.DOCKED_RIGHT;
- case WindowManager.DOCKED_TOP:
- return WindowManager.DOCKED_BOTTOM;
- case WindowManager.DOCKED_RIGHT:
- return WindowManager.DOCKED_LEFT;
- case WindowManager.DOCKED_BOTTOM:
- return WindowManager.DOCKED_TOP;
+ case DOCKED_LEFT:
+ return DOCKED_RIGHT;
+ case DOCKED_TOP:
+ return DOCKED_BOTTOM;
+ case DOCKED_RIGHT:
+ return DOCKED_LEFT;
+ case DOCKED_BOTTOM:
+ return DOCKED_TOP;
default:
- return WindowManager.DOCKED_INVALID;
+ return DOCKED_INVALID;
}
}
}
diff --git a/core/java/com/android/internal/util/MessageUtils.java b/core/java/com/android/internal/util/MessageUtils.java
new file mode 100644
index 0000000..1014bfd
--- /dev/null
+++ b/core/java/com/android/internal/util/MessageUtils.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.os.Message;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.lang.reflect.Field;
+
+/**
+ * Static utility class for dealing with {@link Message} objects.
+ */
+public class MessageUtils {
+
+ private static final String TAG = MessageUtils.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ /** Thrown when two different constants have the same value. */
+ public static class DuplicateConstantError extends Error {
+ private DuplicateConstantError() {}
+ public DuplicateConstantError(String name1, String name2, int value) {
+ super(String.format("Duplicate constant value: both %s and %s = %d",
+ name1, name2, value));
+ }
+ }
+
+ /**
+ * Finds the names of integer constants. Searches the specified {@code classes}, looking for
+ * accessible static integer fields whose names begin with one of the specified {@prefixes}.
+ *
+ * @param classes the classes to examine.
+ * @prefixes only consider fields names starting with one of these prefixes.
+ * @return a {@link SparseArray} mapping integer constants to their names.
+ */
+ public static SparseArray<String> findMessageNames(Class[] classes, String[] prefixes) {
+ SparseArray<String> messageNames = new SparseArray<>();
+ for (Class c : classes) {
+ String className = c.getName();
+ if (DBG) Log.d(TAG, "Examining class " + className);
+
+ Field[] fields;
+ try {
+ fields = c.getDeclaredFields();
+ } catch (SecurityException e) {
+ Log.e(TAG, "Can't list fields of class " + className);
+ continue;
+ }
+
+ for (Field field : fields) {
+ String name = field.getName();
+
+ for (String prefix : prefixes) {
+ // Does this look like a constant?
+ if (!name.startsWith(prefix)) {
+ continue;
+ }
+
+ try {
+ // TODO: can we have the caller try to access the field instead, so we don't
+ // expose constants it does not have access to?
+ field.setAccessible(true);
+
+ // Fetch the constant's value.
+ int value;
+ try {
+ value = field.getInt(null);
+ } catch (IllegalArgumentException | ExceptionInInitializerError e) {
+ // The field is not an integer (or short or byte), or c's static
+ // initializer failed and we have no idea what its value is.
+ // Either way, give up on this field.
+ break;
+ }
+
+ // Check for duplicate values.
+ String previousName = messageNames.get(value);
+ if (previousName != null && !previousName.equals(name)) {
+ throw new DuplicateConstantError(name, previousName, value);
+ }
+
+ messageNames.put(value, name);
+ if (DBG) {
+ Log.d(TAG, String.format("Found constant: %s.%s = %d",
+ className, name, value));
+ }
+ } catch (SecurityException | IllegalAccessException e) {
+ // Not allowed to make the field accessible, or no access. Ignore.
+ continue;
+ }
+ }
+ }
+ }
+ return messageNames;
+ }
+
+ /**
+ * Default prefixes for constants.
+ */
+ public static final String[] DEFAULT_PREFIXES = {"CMD_", "EVENT_"};
+
+ /**
+ * Finds the names of integer constants. Searches the specified {@code classes}, looking for
+ * accessible static integer values whose names begin with {@link #DEFAULT_PREFIXES}.
+ *
+ * @param classNames the classes to examine.
+ * @prefixes only consider fields names starting with one of these prefixes.
+ * @return a {@link SparseArray} mapping integer constants to their names.
+ */
+ public static SparseArray<String> findMessageNames(Class[] classNames) {
+ return findMessageNames(classNames, DEFAULT_PREFIXES);
+ }
+}
+
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index a106f48..5992f7a 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -64,5 +64,6 @@
public static final int BASE_NETWORK_AGENT = 0x00081000;
public static final int BASE_NETWORK_MONITOR = 0x00082000;
public static final int BASE_NETWORK_FACTORY = 0x00083000;
+ public static final int BASE_ETHERNET = 0x00084000;
//TODO: define all used protocols
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 94790c1..fc67245 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -17,6 +17,7 @@
package com.android.internal.view;
import android.os.Bundle;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
@@ -454,4 +455,9 @@
}
return result;
}
+
+ public Handler getHandler() {
+ // Nothing should happen when called from input method.
+ return null;
+ }
}
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index b45fd06..6bba1b3 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -21,6 +21,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.RemoteViews;
@@ -31,16 +32,16 @@
* @hide
*/
@RemoteViews.RemoteView
-public class MediaNotificationView extends RelativeLayout {
+public class MediaNotificationView extends FrameLayout {
private final int mMaxImageSize;
- private final int mImageMarginBottom;
private final int mImageMinTopMargin;
private final int mNotificationContentMarginEnd;
private final int mNotificationContentImageMarginEnd;
private ImageView mRightIcon;
private View mActions;
private View mHeader;
+ private View mMainColumn;
public MediaNotificationView(Context context) {
this(context, null);
@@ -61,39 +62,49 @@
if (hasIcon && mode != MeasureSpec.UNSPECIFIED) {
measureChild(mActions, widthMeasureSpec, heightMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
size = size - mActions.getMeasuredWidth();
ViewGroup.MarginLayoutParams layoutParams =
(MarginLayoutParams) mRightIcon.getLayoutParams();
- size -= layoutParams.getMarginEnd();
+ int imageEndMargin = layoutParams.getMarginEnd();
+ size -= imageEndMargin;
size = Math.min(size, mMaxImageSize);
size = Math.max(size, mRightIcon.getMinimumWidth());
layoutParams.width = size;
layoutParams.height = size;
- // because we can't allign it to the bottom with a margin, we add a topmargin to it
- layoutParams.topMargin = height - size - mImageMarginBottom;
- // If the topMargin is high enough we can also remove the header constraint!
- if (layoutParams.topMargin >= mImageMinTopMargin) {
- resetHeaderIndention();
- } else {
- int paddingEnd = mNotificationContentImageMarginEnd;
- ViewGroup.MarginLayoutParams headerParams =
- (MarginLayoutParams) mHeader.getLayoutParams();
- headerParams.setMarginEnd(size + layoutParams.getMarginEnd());
- if (mHeader.getPaddingEnd() != paddingEnd) {
- mHeader.setPadding(
- isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
- mHeader.getPaddingTop(),
- isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
- mHeader.getPaddingBottom());
- mHeader.setLayoutParams(headerParams);
- }
- }
mRightIcon.setLayoutParams(layoutParams);
- } else if (!hasIcon && mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
- resetHeaderIndention();
+
+ // lets ensure that the main column doesn't run into the image
+ ViewGroup.MarginLayoutParams mainParams
+ = (MarginLayoutParams) mMainColumn.getLayoutParams();
+ int marginEnd = size + imageEndMargin + mNotificationContentMarginEnd;
+ if (marginEnd != mainParams.getMarginEnd()) {
+ mainParams.setMarginEnd(marginEnd);
+ mMainColumn.setLayoutParams(mainParams);
+ }
+
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ ViewGroup.MarginLayoutParams iconParams =
+ (MarginLayoutParams) mRightIcon.getLayoutParams();
+ int topMargin = getMeasuredHeight() - mRightIcon.getMeasuredHeight()
+ - iconParams.bottomMargin;
+ // If the topMargin is high enough we can also remove the header constraint!
+ if (!hasIcon || topMargin >= mImageMinTopMargin) {
+ resetHeaderIndention();
+ } else {
+ int paddingEnd = mNotificationContentImageMarginEnd;
+ ViewGroup.MarginLayoutParams headerParams =
+ (MarginLayoutParams) mHeader.getLayoutParams();
+ headerParams.setMarginEnd(mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd());
+ if (mHeader.getPaddingEnd() != paddingEnd) {
+ mHeader.setPadding(
+ isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
+ mHeader.getPaddingTop(),
+ isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
+ mHeader.getPaddingBottom());
+ mHeader.setLayoutParams(headerParams);
+ }
+ }
}
private void resetHeaderIndention() {
@@ -115,8 +126,6 @@
super(context, attrs, defStyleAttr, defStyleRes);
mMaxImageSize = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.media_notification_expanded_image_max_size);
- mImageMarginBottom = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.media_notification_expanded_image_margin_bottom);
mImageMinTopMargin = (int) (context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_top)
+ getResources().getDisplayMetrics().density * 2);
@@ -132,5 +141,6 @@
mRightIcon = (ImageView) findViewById(com.android.internal.R.id.right_icon);
mActions = findViewById(com.android.internal.R.id.media_actions);
mHeader = findViewById(com.android.internal.R.id.notification_header);
+ mMainColumn = findViewById(com.android.internal.R.id.notification_main_column);
}
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 1b6b53a..8b686b7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -177,8 +177,7 @@
com_android_internal_net_NetworkStatsFactory.cpp \
com_android_internal_os_Zygote.cpp \
com_android_internal_util_VirtualRefBasePtr.cpp \
- com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp \
- android_os_HardwarePropertiesManager.cpp
+ com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 223fc1a..017fb53 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -198,7 +198,6 @@
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
-extern int register_android_os_HardwarePropertiesManager(JNIEnv *env);
static AndroidRuntime* gCurRuntime = NULL;
@@ -1390,7 +1389,6 @@
REG_JNI(register_android_animation_PropertyValuesHolder),
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
- REG_JNI(register_android_os_HardwarePropertiesManager),
};
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
index ae99f0b..731d22a 100644
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
@@ -39,7 +39,6 @@
#include <SkPoint.h>
#include <SkRect.h>
#include <SkTypeface.h>
-#include <SkUtils.h>
#include <hb.h>
@@ -82,17 +81,16 @@
static hb_bool_t harfbuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoint_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* userData)
{
HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData);
+ SkPaint* paint = hbFontData->m_paint;
+ paint->setTextEncoding(SkPaint::kUTF32_TextEncoding);
if (unicode > 0x10ffff) {
unicode = 0xfffd;
}
- SkPaint* paint = hbFontData->m_paint;
- // It would be better to use kUTF32_TextEncoding directly
- paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ SkUnichar unichar = unicode;
+
uint16_t glyph16;
- uint16_t unichar[2];
- size_t size = SkUTF16_FromUnichar(unicode, unichar);
- paint->textToGlyphs(unichar, size * sizeof(*unichar), &glyph16);
+ paint->textToGlyphs(&unichar, sizeof(unichar), &glyph16);
*glyph = glyph16;
return !!*glyph;
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index a3214eb..d00e94c 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -654,15 +654,14 @@
size_t measuredCount = 0;
float measured = 0;
- Layout layout;
- MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, 0, count, count);
- float* advances = new float[count];
- layout.getAdvances(advances);
+ std::unique_ptr<float[]> advancesArray(new float[count]);
+ MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count,
+ advancesArray.get());
for (int i = 0; i < count; i++) {
// traverse in the given direction
int index = forwardScan ? i : (count - i - 1);
- float width = advances[index];
+ float width = advancesArray[index];
if (measured + width > maxWidth) {
break;
}
@@ -672,7 +671,6 @@
}
measured += width;
}
- delete[] advances;
if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
@@ -824,10 +822,15 @@
static jfloat doRunAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[],
jint start, jint count, jint bufSize, jboolean isRtl, jint offset) {
- Layout layout;
int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize);
- return getRunAdvance(layout, buf, start, count, offset);
+ if (offset == count) {
+ return MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count,
+ bufSize, nullptr);
+ }
+ std::unique_ptr<float[]> advancesArray(new float[count]);
+ MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
+ advancesArray.get());
+ return getRunAdvance(advancesArray.get(), buf, start, count, offset);
}
static jfloat getRunAdvance___CIIIIZI_F(JNIEnv *env, jclass, jlong paintHandle,
@@ -845,11 +848,13 @@
static jint doOffsetForAdvance(const Paint* paint, TypefaceImpl* typeface, const jchar buf[],
jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) {
- Layout layout;
int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
- MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, buf, start, count, bufSize);
- return getOffsetForAdvance(layout, buf, start, count, advance);
+ std::unique_ptr<float[]> advancesArray(new float[count]);
+ MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize,
+ advancesArray.get());
+ return getOffsetForAdvance(advancesArray.get(), buf, start, count, advance);
}
+
static jint getOffsetForAdvance___CIIIIZF_I(JNIEnv *env, jclass, jlong paintHandle,
jlong typefaceHandle, jcharArray text, jint start, jint end, jint contextStart,
jint contextEnd, jboolean isRtl, jfloat advance) {
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index ba0876d..defb88a 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -39,23 +39,6 @@
int ifc_enable(const char *ifname);
int ifc_disable(const char *ifname);
int ifc_reset_connections(const char *ifname, int reset_mask);
-
-int dhcp_start(const char * const ifname);
-int dhcp_start_renew(const char * const ifname);
-int dhcp_get_results(const char * const ifname,
- const char *ipaddr,
- const char *gateway,
- uint32_t *prefixLength,
- const char *dns[],
- const char *server,
- uint32_t *lease,
- const char *vendorInfo,
- const char *domains,
- const char *mtu);
-
-int dhcp_stop(const char *ifname);
-int dhcp_release_lease(const char *ifname);
-char *dhcp_get_errmsg();
}
#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
@@ -64,22 +47,6 @@
static const uint16_t kDhcpClientPort = 68;
-/*
- * The following remembers the jfieldID's of the fields
- * of the DhcpInfo Java object, so that we don't have
- * to look them up every time.
- */
-static struct fieldIds {
- jmethodID clear;
- jmethodID setIpAddress;
- jmethodID setGateway;
- jmethodID addDns;
- jmethodID setDomains;
- jmethodID setServerAddress;
- jmethodID setLeaseDuration;
- jmethodID setVendorInfo;
-} dhcpResultsFieldIds;
-
static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
jstring ifname, jint mask)
{
@@ -95,137 +62,6 @@
return (jint)result;
}
-static jboolean android_net_utils_getDhcpResults(JNIEnv* env, jobject clazz, jstring ifname,
- jobject dhcpResults)
-{
- int result;
- char ipaddr[PROPERTY_VALUE_MAX];
- uint32_t prefixLength;
- char gateway[PROPERTY_VALUE_MAX];
- char dns1[PROPERTY_VALUE_MAX];
- char dns2[PROPERTY_VALUE_MAX];
- char dns3[PROPERTY_VALUE_MAX];
- char dns4[PROPERTY_VALUE_MAX];
- const char *dns[5] = {dns1, dns2, dns3, dns4, NULL};
- char server[PROPERTY_VALUE_MAX];
- uint32_t lease;
- char vendorInfo[PROPERTY_VALUE_MAX];
- char domains[PROPERTY_VALUE_MAX];
- char mtu[PROPERTY_VALUE_MAX];
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- if (nameStr == NULL) return (jboolean)false;
-
- result = ::dhcp_get_results(nameStr, ipaddr, gateway, &prefixLength,
- dns, server, &lease, vendorInfo, domains, mtu);
- if (result != 0) {
- ALOGD("dhcp_get_results failed : %s (%s)", nameStr, ::dhcp_get_errmsg());
- }
-
- env->ReleaseStringUTFChars(ifname, nameStr);
- if (result == 0) {
- env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
-
- // set the linkAddress
- // dhcpResults->addLinkAddress(inetAddress, prefixLength)
- result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setIpAddress,
- env->NewStringUTF(ipaddr), prefixLength);
- }
-
- if (result == 0) {
- // set the gateway
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.setGateway, env->NewStringUTF(gateway));
- }
-
- if (result == 0) {
- // dhcpResults->addDns(new InetAddress(dns1))
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1));
- }
-
- if (result == 0) {
- env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains,
- env->NewStringUTF(domains));
-
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2));
-
- if (result == 0) {
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3));
- if (result == 0) {
- result = env->CallBooleanMethod(dhcpResults,
- dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4));
- }
- }
- }
-
- if (result == 0) {
- // dhcpResults->setServerAddress(new InetAddress(server))
- result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress,
- env->NewStringUTF(server));
- }
-
- if (result == 0) {
- // dhcpResults->setLeaseDuration(lease)
- env->CallVoidMethod(dhcpResults,
- dhcpResultsFieldIds.setLeaseDuration, lease);
-
- // dhcpResults->setVendorInfo(vendorInfo)
- env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setVendorInfo,
- env->NewStringUTF(vendorInfo));
- }
- return (jboolean)(result == 0);
-}
-
-static jboolean android_net_utils_startDhcp(JNIEnv* env, jobject clazz, jstring ifname)
-{
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- if (nameStr == NULL) return (jboolean)false;
- if (::dhcp_start(nameStr) != 0) {
- ALOGD("dhcp_start failed : %s", nameStr);
- return (jboolean)false;
- }
- return (jboolean)true;
-}
-
-static jboolean android_net_utils_startDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname)
-{
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- if (nameStr == NULL) return (jboolean)false;
- if (::dhcp_start_renew(nameStr) != 0) {
- ALOGD("dhcp_start_renew failed : %s", nameStr);
- return (jboolean)false;
- }
- return (jboolean)true;
-}
-
-static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::dhcp_stop(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jboolean)(result == 0);
-}
-
-static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::dhcp_release_lease(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jboolean)(result == 0);
-}
-
-static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
-{
- return env->NewStringUTF(::dhcp_get_errmsg());
-}
-
static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
{
int fd = jniGetFDFromFileDescriptor(env, javaFd);
@@ -305,12 +141,6 @@
static const JNINativeMethod gNetworkUtilMethods[] = {
/* name, signature, funcPtr */
{ "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections },
- { "startDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcp },
- { "startDhcpRenew", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcpRenew },
- { "getDhcpResults", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_getDhcpResults },
- { "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
- { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
- { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
{ "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
{ "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
@@ -322,24 +152,6 @@
int register_android_net_NetworkUtils(JNIEnv* env)
{
- jclass dhcpResultsClass = FindClassOrDie(env, "android/net/DhcpResults");
-
- dhcpResultsFieldIds.clear = GetMethodIDOrDie(env, dhcpResultsClass, "clear", "()V");
- dhcpResultsFieldIds.setIpAddress =GetMethodIDOrDie(env, dhcpResultsClass, "setIpAddress",
- "(Ljava/lang/String;I)Z");
- dhcpResultsFieldIds.setGateway = GetMethodIDOrDie(env, dhcpResultsClass, "setGateway",
- "(Ljava/lang/String;)Z");
- dhcpResultsFieldIds.addDns = GetMethodIDOrDie(env, dhcpResultsClass, "addDns",
- "(Ljava/lang/String;)Z");
- dhcpResultsFieldIds.setDomains = GetMethodIDOrDie(env, dhcpResultsClass, "setDomains",
- "(Ljava/lang/String;)V");
- dhcpResultsFieldIds.setServerAddress = GetMethodIDOrDie(env, dhcpResultsClass,
- "setServerAddress", "(Ljava/lang/String;)Z");
- dhcpResultsFieldIds.setLeaseDuration = GetMethodIDOrDie(env, dhcpResultsClass,
- "setLeaseDuration", "(I)V");
- dhcpResultsFieldIds.setVendorInfo = GetMethodIDOrDie(env, dhcpResultsClass, "setVendorInfo",
- "(Ljava/lang/String;)V");
-
return RegisterMethodsOrDie(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
NELEM(gNetworkUtilMethods));
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index cd2c0d6..07868c5 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -164,6 +164,13 @@
mPendingAnimatingRenderNodes.clear();
}
+ void destroy() {
+ for (auto& renderNode : mPendingAnimatingRenderNodes) {
+ renderNode->animators().endAllStagingAnimators();
+ }
+ mPendingAnimatingRenderNodes.clear();
+ }
+
private:
sp<Looper> mLooper;
JavaVM* mVm;
@@ -476,7 +483,9 @@
}
static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
- jlong proxyPtr) {
+ jlong proxyPtr, jlong rootNodePtr) {
+ RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
+ rootRenderNode->destroy();
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->destroy();
}
@@ -698,7 +707,7 @@
{ "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
{ "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
- { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
+ { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
{ "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
{ "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
{ "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4194aa4..612f4df 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -608,8 +608,12 @@
jlong capabilities = 0;
// Grant CAP_WAKE_ALARM to the Bluetooth process.
+ // Additionally, allow bluetooth to open packet sockets so it can start the DHCP client.
+ // TODO: consider making such functionality an RPC to netd.
if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
capabilities |= (1LL << CAP_WAKE_ALARM);
+ capabilities |= (1LL << CAP_NET_RAW);
+ capabilities |= (1LL << CAP_NET_BIND_SERVICE);
}
// Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7699da7..eeff00f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -237,12 +237,21 @@
<protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
- <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
+ <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
+ <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+ <protected-broadcast android:name="com.android.nfc.action.LLCP_UP" />
+ <protected-broadcast android:name="com.android.nfc.action.LLCP_DOWN" />
+ <protected-broadcast android:name="com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.ALLOW_CONNECT" />
+ <protected-broadcast android:name="com.android.nfc.handover.action.DENY_CONNECT" />
<protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
<protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
<protected-broadcast android:name="com.android.nfc_extras.action.AID_SELECTED" />
-
- <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+ <!-- For NFC to BT handover -->
+ <protected-broadcast android:name="android.btopp.intent.action.WHITELIST_DEVICE" />
+ <protected-broadcast android:name="android.btopp.intent.action.STOP_HANDOVER_TRANSFER" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND" />
+ <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
<protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
<protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
@@ -443,6 +452,8 @@
<protected-broadcast android:name="android.bluetooth.input.profile.action.HANDSHAKE" />
<protected-broadcast android:name="android.bluetooth.input.profile.action.REPORT" />
+ <protected-broadcast android:name="android.intent.action.TWILIGHT_CHANGED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -1997,6 +2008,12 @@
<permission android:name="android.permission.UPDATE_APP_OPS_STATS"
android:protectionLevel="signature|privileged|installer" />
+ <!-- Allows an application to update the user app op restrictions.
+ Not for use by third party apps.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS"
+ android:protectionLevel="signature|installer" />
+
<!-- @SystemApi Allows an application to open windows that are for use by parts
of the system user interface.
<p>Not for use by third-party applications.
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index aa78eff..a5ed187 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -19,41 +19,45 @@
<com.android.internal.widget.MediaNotificationView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
- android:layout_height="126dp"
+ android:layout_height="wrap_content"
android:background="#00000000"
android:tag="bigMediaNarrow"
>
<include layout="@layout/notification_template_header"
android:layout_width="match_parent"
android:layout_height="48dp"
- android:layout_alignParentStart="true"/>
+ android:layout_gravity="start"/>
<LinearLayout
- android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/notification_content_margin_top"
- android:layout_marginStart="@dimen/notification_content_margin_start"
- android:layout_marginBottom="@dimen/notification_content_margin_bottom"
- android:layout_marginEnd="@dimen/notification_content_margin_end"
- android:layout_toStartOf="@id/right_icon"
- android:minHeight="@dimen/notification_min_content_height"
android:orientation="vertical"
>
- <include layout="@layout/notification_template_part_line1" />
- <include layout="@layout/notification_template_text" />
- </LinearLayout>
- <LinearLayout
- android:id="@+id/media_actions"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentStart="true"
- android:paddingStart="8dp"
- android:paddingBottom="8dp"
- android:orientation="horizontal"
- android:layoutDirection="ltr"
- >
- <!-- media buttons will be added here -->
+ <LinearLayout
+ android:id="@+id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_content_margin_top"
+ android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginBottom="@dimen/notification_content_margin_bottom"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:minHeight="@dimen/notification_min_content_height"
+ android:orientation="vertical"
+ >
+ <include layout="@layout/notification_template_part_line1" />
+ <include layout="@layout/notification_template_text" />
+ </LinearLayout>
+ <LinearLayout
+ android:id="@+id/media_actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-15dp"
+ android:paddingStart="8dp"
+ android:paddingBottom="8dp"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ >
+ <!-- media buttons will be added here -->
+ </LinearLayout>
</LinearLayout>
<ImageView android:id="@+id/right_icon"
@@ -61,9 +65,8 @@
android:layout_height="@dimen/media_notification_expanded_image_max_size"
android:minWidth="40dp"
android:layout_marginEnd="16dp"
- android:layout_marginTop="16dp"
- android:layout_alignParentEnd="true"
- android:layout_alignParentTop="true"
+ android:layout_marginBottom="16dp"
+ android:layout_gravity="bottom|end"
android:scaleType="centerCrop"
/>
</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index aea9b44..cda0636 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -36,6 +36,7 @@
android:tag="media"
>
<LinearLayout
+ android:id="@+id/notification_content_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_vertical"
@@ -45,7 +46,6 @@
android:orientation="vertical"
>
<include layout="@layout/notification_template_part_line1"/>
- <include layout="@layout/notification_template_progress"/>
<include layout="@layout/notification_template_text"/>
</LinearLayout>
<LinearLayout
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index f91bcd0..4b81987 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -914,6 +914,17 @@
<p>The default value of this attribute is <code>false</code>. -->
<attr name="restoreAnyVersion" format="boolean" />
+ <!-- Indicates that full-data backup operations for this application may
+ be performed even if the application is in a foreground-equivalent
+ state. <em>Use with caution!</em> Setting this flag to <code>true</code>
+ can impact app behavior while the user is interacting with the device.
+
+ <p>If unspecified, the default value of this attribute is <code>false</code>,
+ which means that the OS will avoid backing up the application while it is
+ running in the foreground (such as a music app that is actively playing
+ music via a service in the startForeground() state). -->
+ <attr name="backupInForeground" format="boolean" />
+
<!-- The default install location defined by an application. -->
<attr name="installLocation">
<!-- Let the system decide ideal install location -->
@@ -1247,6 +1258,7 @@
<attr name="killAfterRestore" />
<attr name="restoreNeedsApplication" />
<attr name="restoreAnyVersion" />
+ <attr name="backupInForeground" />
<attr name="neverEncrypt" />
<!-- Request that your application's processes be created with
a large Dalvik heap. This applies to <em>all</em> processes
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 016ed60..3a185d6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1992,10 +1992,10 @@
See {@link com.android.server.notification.NotificationSignalExtractor} -->
<string-array name="config_notificationSignalExtractors">
<item>com.android.server.notification.ValidateNotificationPeople</item>
- <item>com.android.server.notification.TopicPriorityExtractor</item>
- <item>com.android.server.notification.TopicImportanceExtractor</item>
+ <item>com.android.server.notification.PriorityExtractor</item>
+ <item>com.android.server.notification.ImportanceExtractor</item>
<item>com.android.server.notification.NotificationIntrusivenessExtractor</item>
- <item>com.android.server.notification.TopicVisibilityExtractor</item>
+ <item>com.android.server.notification.VisibilityExtractor</item>
</string-array>
<!-- Flag indicating that this device does not rotate and will always remain in its default
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8e86f78..1005704 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -56,6 +56,10 @@
calculate the bounds of the stacks-->
<dimen name="docked_stack_divider_insets">19dp</dimen>
+ <!-- To how much the docked stack gets reduced when we decide to minimize the docked stack, i.e.
+ when the user opens homescreen. -->
+ <dimen name="docked_stack_minimize_thickness">8dp</dimen>
+
<!-- Min width for a tablet device -->
<dimen name="min_xlarge_screen_width">800dp</dimen>
@@ -146,9 +150,6 @@
<!-- The margin on the end of the content view with a picture.-->
<dimen name="notification_content_picture_margin">56dp</dimen>
- <!-- The margin on the end of the content view with a picture in the compact media.-->
- <dimen name="notification_content_picture_margin_media">72dp</dimen>
-
<!-- height of the content margin to accomodate for the header -->
<dimen name="notification_content_margin_top">30dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 894fd37..13812630 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2701,6 +2701,7 @@
<public type="attr" name="hotSpotX" />
<public type="attr" name="hotSpotY" />
<public type="attr" name="version" />
+ <public type="attr" name="backupInForeground" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 68afaba..da88146 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2922,9 +2922,9 @@
<!-- Title of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
<string name="share_remote_bugreport_notification_title">Share bug report?</string>
<!-- Title of notification shown to indicate that bug report is still being collected after sharing was accepted. -->
- <string name="sharing_remote_bugreport_notification_title">Sharing bug report</string>
+ <string name="sharing_remote_bugreport_notification_title">Sharing bug report\u2026</string>
<!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
- <string name="share_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared. This may temporarily slow down your device.</string>
+ <string name="share_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared and your device may temporarily slow down.</string>
<!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
<string name="share_finished_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared.</string>
<!-- Message of notification shown to shown to indicate that bug report is still being collected after sharing was accepted. -->
@@ -4162,9 +4162,7 @@
<item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
</plurals>
- <string name="default_notification_topic_label">Miscellaneous</string>
-
- <string name="importance_from_topic">You set the importance of these notifications.</string>
+ <string name="importance_from_user">You set the importance of these notifications.</string>
<string name="importance_from_person">This is important because of the people involved.</string>
<!-- Message to user that app trying to create user for an account that already exists. [CHAR LIMIT=none] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2d3ad17..746e7fd 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1506,6 +1506,7 @@
<java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
<java-symbol type="dimen" name="docked_stack_divider_thickness" />
<java-symbol type="dimen" name="docked_stack_divider_insets" />
+ <java-symbol type="dimen" name="docked_stack_minimize_thickness" />
<java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
<java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
<java-symbol type="dimen" name="navigation_bar_height" />
@@ -2388,7 +2389,6 @@
<java-symbol type="string" name="config_iccHotswapPromptForRestartDialogComponent" />
<java-symbol type="string" name="config_packagedKeyboardName" />
- <java-symbol type="string" name="default_notification_topic_label" />
<java-symbol type="bool" name="config_forceWindowDrawsStatusBarBackground" />
<java-symbol type="color" name="system_bar_background_semi_transparent" />
@@ -2427,7 +2427,7 @@
<java-symbol type="dimen" name="notification_content_margin_end" />
<java-symbol type="dimen" name="notification_content_picture_margin" />
<java-symbol type="dimen" name="notification_content_margin_top" />
- <java-symbol type="string" name="importance_from_topic" />
+ <java-symbol type="string" name="importance_from_user" />
<java-symbol type="string" name="importance_from_person" />
<java-symbol type="layout" name="work_widget_mask_view" />
@@ -2512,13 +2512,14 @@
<java-symbol type="dimen" name="media_notification_expanded_image_max_size" />
<java-symbol type="dimen" name="media_notification_expanded_image_margin_bottom" />
<java-symbol type="dimen" name="notification_content_image_margin_end" />
- <java-symbol type="dimen" name="notification_content_picture_margin_media" />
<java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
<java-symbol type="layout" name="app_anr_dialog" />
<java-symbol type="id" name="aerr_wait" />
+ <java-symbol type="id" name="notification_content_container" />
+
<!-- Encryption notification while accounts are locked by credential encryption -->
<java-symbol type="string" name="user_encrypted_title" />
<java-symbol type="string" name="user_encrypted_message" />
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk
index 7322e8d..9e45d09 100644
--- a/core/tests/coretests/apks/install_jni_lib/Android.mk
+++ b/core/tests/coretests/apks/install_jni_lib/Android.mk
@@ -22,6 +22,8 @@
LOCAL_SHARED_LIBRARIES := \
libnativehelper
+LOCAL_CFLAGS += -Wall -Werror
+
LOCAL_MODULE := libframeworks_coretests_jni
# this does not prevent build system
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
index 3e83010..8d91192 100644
--- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -37,7 +37,7 @@
/*
* JNI Initialization
*/
-jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
+jint JNI_OnLoad(JavaVM *jvm, void */* reserved */) {
JNIEnv *e;
int status;
diff --git a/core/tests/coretests/src/android/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index c3afbf6..3869cd2 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -66,7 +66,7 @@
assertEquals("Excluding files when there was no <exclude/> tag.", 0, excludesSet.size());
assertEquals("Unexpected number of <include/>s", 1, includeMap.size());
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getFilesDir(), "onlyInclude.txt").getCanonicalPath(),
@@ -99,7 +99,7 @@
FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getFilesDir(), "include.txt").getCanonicalPath(),
@@ -128,15 +128,16 @@
FullBackup.BackupScheme bs = FullBackup.getBackupSchemeForTest(mContext);
bs.parseBackupSchemeFromXmlLocked(mXpp, excludesSet, includeMap);
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertEquals("Didn't find expected file domain include.", 1, fileDomainIncludes.size());
assertEquals("Invalid path parsed for <include/>",
new File(mContext.getFilesDir(), "include1.txt").getCanonicalPath(),
fileDomainIncludes.iterator().next());
Set<String> databaseDomainIncludes = includeMap.get(FullBackup.DATABASE_TREE_TOKEN);
+ // Three expected here because of "-journal" and "-wal" files
assertEquals("Didn't find expected database domain include.",
- 2, databaseDomainIncludes.size()); // two expected here because of "-journal" file
+ 3, databaseDomainIncludes.size());
assertTrue("Invalid path parsed for <include/>",
databaseDomainIncludes.contains(
new File(mContext.getDatabasePath("foo").getParentFile(), "include2.txt")
@@ -147,6 +148,12 @@
mContext.getDatabasePath("foo").getParentFile(),
"include2.txt-journal")
.getCanonicalPath()));
+ assertTrue("Invalid path parsed for <include/>",
+ databaseDomainIncludes.contains(
+ new File(
+ mContext.getDatabasePath("foo").getParentFile(),
+ "include2.txt-wal")
+ .getCanonicalPath()));
List<String> sharedPrefDomainIncludes = new ArrayList<String>(
includeMap.get(FullBackup.SHAREDPREFS_TREE_TOKEN));
@@ -168,7 +175,7 @@
sharedPrefDomainIncludes.get(2));
- assertEquals("Unexpected number of <exclude/>s", 6, excludesSet.size());
+ assertEquals("Unexpected number of <exclude/>s", 7, excludesSet.size());
// Sets are annoying to iterate over b/c order isn't enforced - convert to an array and
// sort lexicographically.
List<String> arrayedSet = new ArrayList<String>(excludesSet);
@@ -183,20 +190,24 @@
.getCanonicalPath(),
arrayedSet.get(1));
assertEquals("Invalid path parsed for <exclude/>",
- new File(mContext.getFilesDir(), "exclude1.txt").getCanonicalPath(),
+ new File(mContext.getDatabasePath("foo").getParentFile(), "exclude2.txt-wal")
+ .getCanonicalPath(),
arrayedSet.get(2));
assertEquals("Invalid path parsed for <exclude/>",
+ new File(mContext.getFilesDir(), "exclude1.txt").getCanonicalPath(),
+ arrayedSet.get(3));
+ assertEquals("Invalid path parsed for <exclude/>",
new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3")
.getCanonicalPath(),
- arrayedSet.get(3));
+ arrayedSet.get(4));
assertEquals("Invalid path parsed for <exclude/>",
new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3.xml")
.getCanonicalPath(),
- arrayedSet.get(4));
+ arrayedSet.get(5));
assertEquals("Invalid path parsed for <exclude/>",
new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude4.xml")
.getCanonicalPath(),
- arrayedSet.get(5));
+ arrayedSet.get(6));
}
public void testParseBackupSchemeFromXml_invalidXmlFails() throws Exception {
@@ -247,7 +258,7 @@
assertEquals("Didn't throw away invalid \"..\" path.", 0, includeMap.size());
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertNull("Didn't throw away invalid \"..\" path.", fileDomainIncludes);
}
public void testDoubleDotInPath_isIgnored() throws Exception {
@@ -261,7 +272,7 @@
assertEquals("Didn't throw away invalid \"..\" path.", 0, includeMap.size());
- Set<String> fileDomainIncludes = includeMap.get(FullBackup.DATA_TREE_TOKEN);
+ Set<String> fileDomainIncludes = includeMap.get(FullBackup.FILES_TREE_TOKEN);
assertNull("Didn't throw away invalid \"..\" path.", fileDomainIncludes);
}
diff --git a/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java b/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java
deleted file mode 100644
index 7088650..0000000
--- a/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import android.os.Debug;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import junit.framework.TestCase;
-
-/**
- * Test for AsyncChannel.
- */
-public class AsyncChannelTest extends TestCase {
- private static final boolean DBG = true;
- private static final boolean WAIT_FOR_DEBUGGER = false;
- private static final String TAG = "AsyncChannelTest";
-
- @SmallTest
- public void test1() throws Exception {
- if (DBG) log("test1");
- if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
- assertTrue(1 == 1);
- }
-
- protected void log(String s) {
- Log.d(TAG, s);
- }
-}
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
index ff5a535..994131a 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/Android.mk
@@ -32,6 +32,8 @@
# All of the shard libraries we link against.
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
# Also need the JNI headers.
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
index 67b12d7..99cf587 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
@@ -22,7 +22,7 @@
#include "jni.h"
static jint
-add(JNIEnv *env, jobject thiz, jint a, jint b) {
+add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
ALOGI("%d + %d = %d", a, b, result);
return result;
@@ -82,7 +82,7 @@
void* venv;
} UnionJNIEnvToVoid;
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
UnionJNIEnvToVoid uenv;
uenv.venv = NULL;
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
index abb1d9f..6c2679b 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/Android.mk
@@ -34,6 +34,8 @@
LOCAL_SHARED_LIBRARIES := \
libutils liblog
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
# Also need the JNI headers.
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
index 342b3bc..0b6d750 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
@@ -22,7 +22,7 @@
#include "jni.h"
static jint
-add(JNIEnv *env, jobject thiz, jint a, jint b) {
+add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
ALOGI("%d + %d = %d", a, b, result);
return result;
@@ -82,7 +82,7 @@
void* venv;
} UnionJNIEnvToVoid;
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
UnionJNIEnvToVoid uenv;
uenv.venv = NULL;
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
index ae8e636..d668f29 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/Android.mk
@@ -33,6 +33,8 @@
LOCAL_LDLIBS = -llog
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
# Also need the JNI headers.
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
index 9b38e3e..3947e21 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
@@ -22,7 +22,7 @@
#include "jni.h"
static jint
-add(JNIEnv *env, jobject thiz, jint a, jint b) {
+add(JNIEnv */* env */, jobject /* thiz */, jint a, jint b) {
int result = a + b;
ALOGI("%d + %d = %d", a, b, result);
return result;
@@ -82,7 +82,7 @@
void* venv;
} UnionJNIEnvToVoid;
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
UnionJNIEnvToVoid uenv;
uenv.venv = NULL;
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
new file mode 100644
index 0000000..f949e1a
--- /dev/null
+++ b/core/tests/utiltests/Android.mk
@@ -0,0 +1,23 @@
+#########################################################################
+# Build FrameworksUtilTests package
+#########################################################################
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := FrameworksUtilTests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/utiltests/AndroidManifest.xml b/core/tests/utiltests/AndroidManifest.xml
new file mode 100644
index 0000000..fecaf8e
--- /dev/null
+++ b/core/tests/utiltests/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.utiltests">
+
+ <uses-permission android:name="android.permission.READ_LOGS" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+ <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+ <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+ <uses-permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+ <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.utiltests"
+ android:label="Frameworks Utility Tests" />
+
+</manifest>
diff --git a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
rename to core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/BitwiseStreamsTest.java b/core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/BitwiseStreamsTest.java
rename to core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/CallbackRegistryTest.java b/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/CallbackRegistryTest.java
rename to core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/CharSequencesTest.java b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/CharSequencesTest.java
rename to core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
similarity index 94%
rename from core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java
rename to core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
index be7116d..5f36c2d 100644
--- a/core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
@@ -42,6 +42,6 @@
out.endDocument();
assertEquals("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
- + "<string name=\"meow\"></string>", stream.toString());
+ + "<string name=\"meow\"></string>\n", stream.toString());
}
}
diff --git a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java b/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java
rename to core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java b/core/tests/utiltests/src/com/android/internal/util/IndentingPrintWriterTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java
rename to core/tests/utiltests/src/com/android/internal/util/IndentingPrintWriterTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/PredicatesTest.java b/core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/PredicatesTest.java
rename to core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/ProcFileReaderTest.java b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/ProcFileReaderTest.java
rename to core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
rename to core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/XmlUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/XmlUtilsTest.java
rename to core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 77748a8..c486c1f 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -154,7 +154,7 @@
private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
/** Local, mutable animator set. */
- private final VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimator();
+ private final VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimator(this);
/**
* The resources against which this drawable was created. Used to attempt
@@ -613,14 +613,12 @@
*/
public void reset() {
mAnimatorSet.reset();
- invalidateSelf();
}
@Override
public void start() {
ensureAnimatorSet();
mAnimatorSet.start();
- invalidateSelf();
}
@NonNull
@@ -639,7 +637,6 @@
@Override
public void stop() {
mAnimatorSet.end();
- invalidateSelf();
}
/**
@@ -659,7 +656,6 @@
}
mAnimatorSet.reverse();
- invalidateSelf();
}
/**
@@ -781,8 +777,10 @@
private WeakReference<RenderNode> mLastSeenTarget = null;
private int mLastListenerId = 0;
private int mPendingAnimationAction = NONE;
+ private final Drawable mDrawable;
- VectorDrawableAnimator() {
+ VectorDrawableAnimator(AnimatedVectorDrawable drawable) {
+ mDrawable = drawable;
mSetPtr = nCreateAnimatorSet();
// Increment ref count on native AnimatorSet, so it doesn't get released before Java
// side is done using it.
@@ -1058,12 +1056,17 @@
return false;
}
+ private void invalidateOwningView() {
+ mDrawable.invalidateSelf();
+ }
+
public void start() {
if (!mInitialized) {
return;
}
if (!useLastSeenTarget()) {
+ invalidateOwningView();
mPendingAnimationAction = START_ANIMATION;
return;
}
@@ -1074,6 +1077,7 @@
mStarted = true;
nStart(mSetPtr, this, ++mLastListenerId);
+ invalidateOwningView();
if (mListener != null) {
mListener.onAnimationStart(null);
}
@@ -1083,6 +1087,7 @@
if (mInitialized && useLastSeenTarget()) {
// If no target has ever been set, no-op
nEnd(mSetPtr);
+ invalidateOwningView();
}
}
@@ -1090,6 +1095,7 @@
if (mInitialized && useLastSeenTarget()) {
// If no target has ever been set, no-op
nReset(mSetPtr);
+ invalidateOwningView();
}
}
@@ -1100,6 +1106,7 @@
return;
}
if (!useLastSeenTarget()) {
+ invalidateOwningView();
mPendingAnimationAction = REVERSE_ANIMATION;
return;
}
@@ -1108,6 +1115,7 @@
}
mStarted = true;
nReverse(mSetPtr, this, ++mLastListenerId);
+ invalidateOwningView();
if (mListener != null) {
mListener.onAnimationStart(null);
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index e6276a4..1321a83 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -233,7 +233,8 @@
// not set up).
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds());
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ spec.isUserAuthenticationValidWhileOnBody());
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -271,7 +272,8 @@
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
KeymasterUtils.addUserAuthArgs(args,
spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds());
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ spec.isUserAuthenticationValidWhileOnBody());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 3a0ff1c..830402a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -344,7 +344,8 @@
// not set up).
KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds());
+ mSpec.getUserAuthenticationValidityDurationSeconds(),
+ mSpec.isUserAuthenticationValidWhileOnBody());
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -529,7 +530,8 @@
KeymasterUtils.addUserAuthArgs(args,
mSpec.isUserAuthenticationRequired(),
- mSpec.getUserAuthenticationValidityDurationSeconds());
+ mSpec.getUserAuthenticationValidityDurationSeconds(),
+ mSpec.isUserAuthenticationValidWhileOnBody());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 8d606bf..5f5f2c2 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -167,6 +167,8 @@
boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
&& (keymasterHwEnforcedUserAuthenticators != 0)
&& (keymasterSwEnforcedUserAuthenticators == 0);
+ boolean userAuthenticationValidWhileOnBody =
+ keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
return new KeyInfo(entryAlias,
insideSecureHardware,
@@ -182,7 +184,8 @@
blockModes,
userAuthenticationRequired,
(int) userAuthenticationValidityDurationSeconds,
- userAuthenticationRequirementEnforcedBySecureHardware);
+ userAuthenticationRequirementEnforcedBySecureHardware,
+ userAuthenticationValidWhileOnBody);
}
@Override
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index cdcc7a2..d660020 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -498,7 +498,8 @@
KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
KeymasterUtils.addUserAuthArgs(importArgs,
spec.isUserAuthenticationRequired(),
- spec.getUserAuthenticationValidityDurationSeconds());
+ spec.getUserAuthenticationValidityDurationSeconds(),
+ spec.isUserAuthenticationValidWhileOnBody());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
spec.getKeyValidityStart());
importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -692,7 +693,8 @@
args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
KeymasterUtils.addUserAuthArgs(args,
params.isUserAuthenticationRequired(),
- params.getUserAuthenticationValidityDurationSeconds());
+ params.getUserAuthenticationValidityDurationSeconds(),
+ params.isUserAuthenticationValidWhileOnBody());
KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
args,
keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index f3fd129..a84e7f34 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -252,6 +252,7 @@
private final int mUserAuthenticationValidityDurationSeconds;
private final byte[] mAttestationChallenge;
private final boolean mUniqueIdIncluded;
+ private final boolean mUserAuthenticationValidWhileOnBody;
/**
* @hide should be built with Builder
@@ -277,7 +278,8 @@
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
byte[] attestationChallenge,
- boolean uniqueIdIncluded) {
+ boolean uniqueIdIncluded,
+ boolean userAuthenticationValidWhileOnBody) {
if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
}
@@ -321,6 +323,7 @@
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
mUniqueIdIncluded = uniqueIdIncluded;
+ mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
}
/**
@@ -587,6 +590,23 @@
}
/**
+ * Returns {@code true} if the key will remain authorized while the device is on the user's
+ * body, even after the validity duration has expired. This option has no effect on keys that
+ * don't have an authentication validity duration, and has no effect if the device lacks a
+ * secure on-body sensor.
+ *
+ * <p>Authorization applies only to secret key and private key operations. Public key operations
+ * are not restricted.
+ *
+ * @see #isUserAuthenticationRequired()
+ * @see #getUserAuthenticationValidityDurationSeconds()
+ * @see Builder#setUserAuthenticationValidWhileOnBody(boolean)
+ */
+ public boolean isUserAuthenticationValidWhileOnBody() {
+ return mUserAuthenticationValidWhileOnBody;
+ }
+
+ /**
* Builder of {@link KeyGenParameterSpec} instances.
*/
public final static class Builder {
@@ -612,6 +632,7 @@
private int mUserAuthenticationValidityDurationSeconds = -1;
private byte[] mAttestationChallenge = null;
private boolean mUniqueIdIncluded = false;
+ private boolean mUserAuthenticationValidWhileOnBody;
/**
* Creates a new instance of the {@code Builder}.
@@ -1061,6 +1082,34 @@
}
/**
+ * Sets whether the key is authorized for use after the authentication validity period is
+ * expired (see {@link #setUserAuthenticationValidityDurationSeconds} and {@link
+ * #setUserAuthenticationRequired}) if the device has a secure on-body sensor and if the
+ * device has not been removed from the user's body since the last successful
+ * authentication.
+ *
+ * <p>On devices that do not have a secure on-body sensor, creating a key with this
+ * parameter set to {@code true} will have no effect; the private or secret key will no
+ * longer be authorized for use after the validity period ends, and a fresh authentication
+ * will be required to use it again.
+ *
+ * <p>Note that "secure" on-body sensors are required by Android to have a secure path to
+ * the secure hardware, but the sensors themselves may not be difficult to fool. It is
+ * recommended that this feature be used to increase slightly the security of keys which
+ * would otherwise have to allow unauthenticated access, or have a very long validity
+ * period. Keys that require high assurance of user authorization should not use this
+ * feature and should set a short validity period.
+ *
+ * @param remainsValid if {@code true}, and if the device supports secure on-body detection,
+ * key will remain valid after authentication validity duration has expired.
+ */
+ @NonNull
+ public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) {
+ mUserAuthenticationValidWhileOnBody = remainsValid;
+ return this;
+ }
+
+ /**
* Builds an instance of {@code KeyGenParameterSpec}.
*/
@NonNull
@@ -1086,7 +1135,8 @@
mUserAuthenticationRequired,
mUserAuthenticationValidityDurationSeconds,
mAttestationChallenge,
- mUniqueIdIncluded);
+ mUniqueIdIncluded,
+ mUserAuthenticationValidWhileOnBody);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index d726880..f77b5ba 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -79,6 +79,7 @@
private final boolean mUserAuthenticationRequired;
private final int mUserAuthenticationValidityDurationSeconds;
private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
+ private final boolean mUserAuthenticationValidWhileOnBody;
/**
* @hide
@@ -97,7 +98,8 @@
@KeyProperties.BlockModeEnum String[] blockModes,
boolean userAuthenticationRequired,
int userAuthenticationValidityDurationSeconds,
- boolean userAuthenticationRequirementEnforcedBySecureHardware) {
+ boolean userAuthenticationRequirementEnforcedBySecureHardware,
+ boolean userAuthenticationValidWhileOnBody) {
mKeystoreAlias = keystoreKeyAlias;
mInsideSecureHardware = insideSecureHardware;
mOrigin = origin;
@@ -116,6 +118,7 @@
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
mUserAuthenticationRequirementEnforcedBySecureHardware =
userAuthenticationRequirementEnforcedBySecureHardware;
+ mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
}
/**
@@ -277,4 +280,14 @@
public boolean isUserAuthenticationRequirementEnforcedBySecureHardware() {
return mUserAuthenticationRequirementEnforcedBySecureHardware;
}
+
+ /**
+ * Returns {@code true} if this key will remain usable after its specified validity duration
+ * for as long as the device remains on the user's body. This is possible only for keys with
+ * a specified validity duration. Always returns {@code false} on devices that lack a secure
+ * on-body sensor.
+ */
+ public boolean isUserAuthenticationValidWhileOnBody() {
+ return mUserAuthenticationValidWhileOnBody;
+ }
}
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index c984439..4700b68 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -214,6 +214,7 @@
private final boolean mRandomizedEncryptionRequired;
private final boolean mUserAuthenticationRequired;
private final int mUserAuthenticationValidityDurationSeconds;
+ private final boolean mUserAuthenticationValidWhileOnBody;
private KeyProtection(
Date keyValidityStart,
@@ -226,7 +227,8 @@
@KeyProperties.BlockModeEnum String[] blockModes,
boolean randomizedEncryptionRequired,
boolean userAuthenticationRequired,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ boolean userAuthenticationValidWhileOnBody) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -240,6 +242,7 @@
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticationRequired = userAuthenticationRequired;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
}
/**
@@ -392,6 +395,23 @@
}
/**
+ * Returns {@code true} if the key will remain authorized while the device is on the user's
+ * body, even after the validity duration has expired. This option has no effect on keys that
+ * don't have an authentication validity duration, and has no effect if the device lacks a
+ * secure on-body sensor.
+ *
+ * <p>Authorization applies only to secret key and private key operations. Public key operations
+ * are not restricted.
+ *
+ * @see #isUserAuthenticationRequired()
+ * @see #getUserAuthenticationValidityDurationSeconds()
+ * @see Builder#setUserAuthenticationValidWhileOnBody(boolean)
+ */
+ public boolean isUserAuthenticationValidWhileOnBody() {
+ return mUserAuthenticationValidWhileOnBody;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -407,6 +427,7 @@
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
private int mUserAuthenticationValidityDurationSeconds = -1;
+ private boolean mUserAuthenticationValidWhileOnBody;
/**
* Creates a new instance of the {@code Builder}.
@@ -680,6 +701,34 @@
}
/**
+ * Sets whether the key is authorized for use after the authentication validity period is
+ * expired (see {@link #setUserAuthenticationValidityDurationSeconds} and {@link
+ * #setUserAuthenticationRequired}) if the device has a secure on-body sensor and if the
+ * device has not been removed from the user's body since the last successful
+ * authentication.
+ *
+ * <p>On devices that do not have a secure on-body sensor, creating a key with this
+ * parameter set to {@code true} will have no effect; the private or secret key will no
+ * longer be authorized for use after the validity period ends, and a fresh authentication
+ * will be required to use it again.
+ *
+ * <p>Note that "secure" on-body sensors are required by Android to have a secure path to
+ * the secure hardware, but the sensors themselves may not be difficult to fool. It is
+ * recommended that this feature be used to increase slightly the security of keys which
+ * would otherwise have to allow unauthenticated access, or have a very long validity
+ * period. Keys that require high assurance of user authorization should not use this
+ * feature and should set a short validity period.
+ *
+ * @param remainsValid if {@code true}, and if the device supports secure on-body detection,
+ * key will remain valid after authentication validity duration has expired.
+ */
+ @NonNull
+ public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) {
+ mUserAuthenticationValidWhileOnBody = remainsValid;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -697,7 +746,8 @@
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticationRequired,
- mUserAuthenticationValidityDurationSeconds);
+ mUserAuthenticationValidityDurationSeconds,
+ mUserAuthenticationValidWhileOnBody);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index feafbfa..3a008bc 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -96,7 +96,8 @@
*/
public static void addUserAuthArgs(KeymasterArguments args,
boolean userAuthenticationRequired,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ boolean userAuthenticationValidWhileOnBody) {
if (!userAuthenticationRequired) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
return;
@@ -119,6 +120,10 @@
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
KeymasterArguments.toUint64(fingerprintOnlySid));
args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
+ if (userAuthenticationValidWhileOnBody) {
+ throw new ProviderException("Key validity extension while device is on-body is not "
+ + "supported for keys requiring fingerprint authentication");
+ }
} else {
// The key is authorized for use for the specified amount of time after the user has
// authenticated. Whatever unlocks the secure lock screen should authorize this key.
@@ -133,6 +138,9 @@
KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
userAuthenticationValidityDurationSeconds);
+ if (userAuthenticationValidWhileOnBody) {
+ args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
+ }
}
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 6257122..8660b75 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -7,7 +7,7 @@
# Enables fine-grained GLES error checking
# If set to true, every GLES call is wrapped & error checked
# Has moderate overhead
-HWUI_ENABLE_OPENGL_VALIDATION := false
+HWUI_ENABLE_OPENGL_VALIDATION := true
hwui_src_files := \
font/CacheTexture.cpp \
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 269e590..0adb21c 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -406,12 +406,16 @@
void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
- addOp(alloc().create_trivial<ArcOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint),
- startAngle, sweepAngle, useCenter));
+ if (fabs(sweepAngle) >= 360.0f) {
+ drawOval(left, top, right, bottom, paint);
+ } else {
+ addOp(alloc().create_trivial<ArcOp>(
+ Rect(left, top, right, bottom),
+ *(mState.currentSnapshot()->transform),
+ getRecordedClip(),
+ refPaint(&paint),
+ startAngle, sweepAngle, useCenter));
+ }
}
void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 3440d03..9595a85 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -162,6 +162,7 @@
renderState.onGLContextCreated();
rtCallback(renderthread::RenderThread::getInstance());
+ renderState.flush(Caches::FlushMode::Full);
renderState.onGLContextDestroyed();
// Restore the previous signal handler
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 20d2f1f..cd9ffc5 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -57,6 +57,22 @@
<< "Clip should be serialized once";
}
+TEST(RecordingCanvas, drawArc) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint());
+ canvas.drawArc(0, 0, 100, 100, 0, 360, true, SkPaint());
+ });
+
+ auto&& ops = dl->getOps();
+ ASSERT_EQ(2u, ops.size()) << "Must be exactly two ops";
+ EXPECT_EQ(RecordedOpId::ArcOp, ops[0]->opId);
+ EXPECT_EQ(Rect(200, 200), ops[0]->unmappedBounds);
+
+ EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId)
+ << "Circular arcs should be converted to ovals";
+ EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds);
+}
+
TEST(RecordingCanvas, drawLines) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
SkPaint paint;
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index 37ef3df79..5ba3f2c 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -73,7 +73,7 @@
private double mBiasUncertaintyInNs;
private double mDriftInNsPerSec;
private double mDriftUncertaintyInNsPerSec;
- private long mTimeOfLastHwClockDiscontinuityInNs;
+ private int mHardwareClockDiscontinuityCount;
GnssClock() {
initialize();
@@ -93,7 +93,7 @@
mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
mDriftInNsPerSec = clock.mDriftInNsPerSec;
mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
- mTimeOfLastHwClockDiscontinuityInNs = clock.mTimeOfLastHwClockDiscontinuityInNs;
+ mHardwareClockDiscontinuityCount = clock.mHardwareClockDiscontinuityCount;
}
/**
@@ -395,17 +395,17 @@
}
/**
- * Gets time of last hardware clock discontinuity.
+ * Gets count of last hardware clock discontinuity.
*/
- public long getTimeOfLastHwClockDiscontinuityInNs() {
- return mTimeOfLastHwClockDiscontinuityInNs;
+ public int getHardwareClockDiscontinuityCount() {
+ return mHardwareClockDiscontinuityCount;
}
/**
- * Sets time of last hardware clock discontinuity.
+ * Sets count of last hardware clock discontinuity.
*/
- public void setTimeOfLastHwClockDiscontinuityInNs(long timeOfLastHwClockDiscontinuityInNs) {
- mTimeOfLastHwClockDiscontinuityInNs = timeOfLastHwClockDiscontinuityInNs;
+ public void setHardwareClockDiscontinuityCount(int value) {
+ mHardwareClockDiscontinuityCount = value;
}
/**
@@ -431,7 +431,7 @@
gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
gpsClock.mDriftInNsPerSec = parcel.readDouble();
gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
- gpsClock.mTimeOfLastHwClockDiscontinuityInNs = parcel.readLong();
+ gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
return gpsClock;
}
@@ -442,6 +442,7 @@
}
};
+ @Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mFlags);
parcel.writeInt(mLeapSecond);
@@ -453,7 +454,7 @@
parcel.writeDouble(mBiasUncertaintyInNs);
parcel.writeDouble(mDriftInNsPerSec);
parcel.writeDouble(mDriftUncertaintyInNsPerSec);
- parcel.writeLong(mTimeOfLastHwClockDiscontinuityInNs);
+ parcel.writeInt(mHardwareClockDiscontinuityCount);
}
@Override
@@ -497,9 +498,9 @@
"DriftUncertaintyInNsPerSec",
hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
- builder.append(String.format(format, "TimeOfLastHwClockDiscontinuityInNs",
+ builder.append(String.format(format, "HardwareClockDiscontinuityCount",
getType() == CLOCK_TYPE_LOCAL_HW_TIME
- ? mTimeOfLastHwClockDiscontinuityInNs : null));
+ ? mHardwareClockDiscontinuityCount : null));
return builder.toString();
}
@@ -515,7 +516,7 @@
resetBiasUncertaintyInNs();
resetDriftInNsPerSec();
resetDriftUncertaintyInNsPerSec();
- setTimeOfLastHwClockDiscontinuityInNs(Long.MIN_VALUE);
+ setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
}
private void setFlag(short flag) {
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index a490685..a619ab2 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -24,15 +24,16 @@
import java.lang.annotation.RetentionPolicy;
/**
- * A class representing a GPS satellite measurement, containing raw and computed information.
+ * A class representing a GNSS satellite measurement, containing raw and computed information.
*/
public final class GnssMeasurement implements Parcelable {
private int mFlags;
private short mSvid;
+ private byte mConstellationType;
private double mTimeOffsetInNs;
private short mState;
- private long mReceivedGpsTowInNs;
- private long mReceivedGpsTowUncertaintyInNs;
+ private long mReceivedSvTimeInNs;
+ private long mReceivedSvTimeUncertaintyInNs;
private double mCn0InDbHz;
private double mPseudorangeRateInMetersPerSec;
private double mPseudorangeRateUncertaintyInMetersPerSec;
@@ -59,8 +60,6 @@
private double mAzimuthInDeg;
private double mAzimuthUncertaintyInDeg;
private boolean mUsedInFix;
- private double mPseudorangeRateCarrierInMetersPerSec;
- private double mPseudorangeRateCarrierUncertaintyInMetersPerSec;
// The following enumerations must be in sync with the values declared in gps.h
@@ -82,8 +81,8 @@
private static final int HAS_TIME_FROM_LAST_BIT = (1<<14);
private static final int HAS_DOPPLER_SHIFT = (1<<15);
private static final int HAS_DOPPLER_SHIFT_UNCERTAINTY = (1<<16);
- private static final int HAS_USED_IN_FIX = (1<<17);
- private static final int GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
+ // private static final int HAS_USED_IN_FIX = (1<<17);
+ private static final int HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
/** The status of 'loss of lock'. */
@Retention(RetentionPolicy.SOURCE)
@@ -127,37 +126,37 @@
public static final byte MULTIPATH_INDICATOR_NOT_USED = 2;
/**
- * The state of GPS receiver the measurement is invalid or unknown.
+ * The state of GNSS receiver the measurement is invalid or unknown.
*/
public static final short STATE_UNKNOWN = 0;
/**
- * The state of the GPS receiver is ranging code lock.
+ * The state of the GNSS receiver is ranging code lock.
*/
public static final short STATE_CODE_LOCK = (1<<0);
/**
- * The state of the GPS receiver is in bit sync.
+ * The state of the GNSS receiver is in bit sync.
*/
public static final short STATE_BIT_SYNC = (1<<1);
/**
- *The state of the GPS receiver is in sub-frame sync.
+ *The state of the GNSS receiver is in sub-frame sync.
*/
public static final short STATE_SUBFRAME_SYNC = (1<<2);
/**
- * The state of the GPS receiver has TOW decoded.
+ * The state of the GNSS receiver has TOW decoded.
*/
public static final short STATE_TOW_DECODED = (1<<3);
/**
- * The state of the GPS receiver contains millisecond ambiguity.
+ * The state of the GNSS receiver contains millisecond ambiguity.
*/
public static final short STATE_MSEC_AMBIGUOUS = (1<<4);
/**
- * All the GPS receiver state flags.
+ * All the GNSS receiver state flags.
*/
private static final short STATE_ALL = STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC
| STATE_TOW_DECODED | STATE_MSEC_AMBIGUOUS;
@@ -199,10 +198,11 @@
public void set(GnssMeasurement measurement) {
mFlags = measurement.mFlags;
mSvid = measurement.mSvid;
+ mConstellationType = measurement.mConstellationType;
mTimeOffsetInNs = measurement.mTimeOffsetInNs;
mState = measurement.mState;
- mReceivedGpsTowInNs = measurement.mReceivedGpsTowInNs;
- mReceivedGpsTowUncertaintyInNs = measurement.mReceivedGpsTowUncertaintyInNs;
+ mReceivedSvTimeInNs = measurement.mReceivedSvTimeInNs;
+ mReceivedSvTimeUncertaintyInNs = measurement.mReceivedSvTimeUncertaintyInNs;
mCn0InDbHz = measurement.mCn0InDbHz;
mPseudorangeRateInMetersPerSec = measurement.mPseudorangeRateInMetersPerSec;
mPseudorangeRateUncertaintyInMetersPerSec =
@@ -231,10 +231,6 @@
mAzimuthInDeg = measurement.mAzimuthInDeg;
mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
mUsedInFix = measurement.mUsedInFix;
- mPseudorangeRateCarrierInMetersPerSec =
- measurement.mPseudorangeRateCarrierInMetersPerSec;
- mPseudorangeRateCarrierUncertaintyInMetersPerSec =
- measurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec;
}
/**
@@ -260,6 +256,21 @@
}
/**
+ * Getst the constellation type.
+ */
+ @GnssStatus.ConstellationType
+ public byte getConstellationType() {
+ return mConstellationType;
+ }
+
+ /**
+ * Sets the constellation type.
+ */
+ public void setConstellationType(@GnssStatus.ConstellationType byte value) {
+ mConstellationType = value;
+ }
+
+ /**
* Gets the time offset at which the measurement was taken in nanoseconds.
* The reference receiver's time is specified by {@link GnssClock#getTimeInNs()} and should be
* interpreted in the same way as indicated by {@link GnssClock#getType()}.
@@ -285,7 +296,7 @@
* Gets per-satellite sync state.
* It represents the current sync state for the associated satellite.
*
- * This value helps interpret {@link #getReceivedGpsTowInNs()}.
+ * This value helps interpret {@link #getReceivedSvTimeInNs()}.
*/
public short getState() {
return mState;
@@ -333,39 +344,92 @@
}
/**
- * Gets the received GPS Time-of-Week at the measurement time, in nanoseconds.
- * The value is relative to the beginning of the current GPS week.
+ * Gets the received GNSS satellite time, at the measurement time, in nanoseconds.
*
- * Given {@link #getState()} of the GPS receiver, the range of this field can be:
- * Searching : [ 0 ] : {@link #STATE_UNKNOWN} is set
- * Ranging code lock : [ 0 1 ms ] : {@link #STATE_CODE_LOCK} is set
- * Bit sync : [ 0 20 ms ] : {@link #STATE_BIT_SYNC} is set
- * Subframe sync : [ 0 6 ms ] : {@link #STATE_SUBFRAME_SYNC} is set
- * TOW decoded : [ 0 1 week ] : {@link #STATE_TOW_DECODED} is set
+ * For GPS & QZSS, this is:
+ * Received GPS Time-of-Week at the measurement time, in nanoseconds.
+ * The value is relative to the beginning of the current GPS week.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range
+ * for this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set
+ * Subframe sync : [ 0 6s ] : STATE_SUBFRAME_SYNC is set
+ * TOW decoded : [ 0 1week ] : STATE_TOW_DECODED is set
+ *
+ * Note well: if there is any ambiguity in integer millisecond,
+ * STATE_MSEC_AMBIGUOUS should be set accordingly, in the 'state' field.
+ *
+ * This value must be populated if 'state' != STATE_UNKNOWN.
+ *
+ * For Glonass, this is:
+ * Received Glonass time of day, at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range for
+ * this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Symbol sync : [ 0 10ms ] : STATE_SYMBOL_SYNC is set
+ * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC is set
+ * String sync : [ 0 2s ] : STATE_GLO_STRING_SYNC is set
+ * Time of day : [ 0 1day ] : STATE_GLO_TOD_DECODED is set
+ *
+ * For Beidou, this is:
+ * Received Beidou time of week, at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range for
+ * this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Bit sync (D2) : [ 0 2ms ] : STATE_BDS_D2_BIT_SYNC is set
+ * Bit sync (D1) : [ 0 20ms ] : STATE_BIT_SYNC is set
+ * Subframe (D2) : [ 0 0.6s ] : STATE_BDS_D2_SUBFRAME_SYNC is set
+ * Subframe (D1) : [ 0 6s ] : STATE_SUBFRAME_SYNC is set
+ * Time of week : [ 0 1week ] : STATE_TOW_DECODED is set
+ *
+ * For Galileo, this is:
+ * Received Galileo time of week, at the measurement time in nanoseconds.
+ *
+ * E1BC code lock : [ 0 4ms ] : STATE_GAL_E1BC_CODE_LOCK is set
+ * E1C 2nd code lock : [ 0 100ms ] : STATE_GAL_E1C_2ND_CODE_LOCK is set
+ *
+ * E1B page : [ 0 2s ] : STATE_GAL_E1B_PAGE_SYNC is set
+ * Time of week : [ 0 1week ] : STATE_GAL_TOW_DECODED is set
+ *
+ * For SBAS, this is:
+ * Received SBAS time, at the measurement time in nanoseconds.
+ *
+ * Given the highest sync state that can be achieved, per each satellite, valid range for
+ * this field can be:
+ * Searching : [ 0 ] : STATE_UNKNOWN
+ * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK is set
+ * Symbol sync : [ 0 2ms ] : STATE_SYMBOL_SYNC is set
+ * Message : [ 0 1s ] : STATE_SBAS_SYNC is set
*/
- public long getReceivedGpsTowInNs() {
- return mReceivedGpsTowInNs;
+ public long getReceivedSvTimeInNs() {
+ return mReceivedSvTimeInNs;
}
/**
- * Sets the received GPS time-of-week in nanoseconds.
+ * Sets the received GNSS time in nanoseconds.
*/
- public void setReceivedGpsTowInNs(long value) {
- mReceivedGpsTowInNs = value;
+ public void setReceivedSvTimeInNs(long value) {
+ mReceivedSvTimeInNs = value;
}
/**
- * Gets the received GPS time-of-week's uncertainty (1-Sigma) in nanoseconds.
+ * Gets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
*/
- public long getReceivedGpsTowUncertaintyInNs() {
- return mReceivedGpsTowUncertaintyInNs;
+ public long getReceivedSvTimeUncertaintyInNs() {
+ return mReceivedSvTimeUncertaintyInNs;
}
/**
- * Sets the received GPS time-of-week's uncertainty (1-Sigma) in nanoseconds.
+ * Sets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
*/
- public void setReceivedGpsTowUncertaintyInNs(long value) {
- mReceivedGpsTowUncertaintyInNs = value;
+ public void setReceivedSvTimeUncertaintyInNs(long value) {
+ mReceivedSvTimeUncertaintyInNs = value;
}
/**
@@ -416,7 +480,7 @@
* value, {@code false} if it contains an uncorrected value.
*/
public boolean isPseudorangeRateCorrected() {
- return !isFlagSet(GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE);
+ return !isFlagSet(HAS_UNCORRECTED_PSEUDORANGE_RATE);
}
/**
@@ -1160,7 +1224,7 @@
}
/**
- * Gets a flag indicating whether the GPS represented by the measurement was used for computing
+ * Gets a flag indicating whether the GNSS represented by the measurement was used for computing
* the most recent fix.
*
* @return A non-null value if the data is available, null otherwise.
@@ -1176,34 +1240,6 @@
mUsedInFix = value;
}
- /**
- * Gets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
- */
- public double getPseudorangeRateCarrierInMetersPerSec() {
- return mPseudorangeRateCarrierInMetersPerSec;
- }
-
- /**
- * Sets pseudorange rate (based on carrier phase changes) at the timestamp in m/s.
- */
- public void setPseudorangeRateCarrierInMetersPerSec(double value) {
- mPseudorangeRateCarrierInMetersPerSec = value;
- }
-
- /**
- * Gets 1-Sigma uncertainty of the pseudorange rate carrier.
- */
- public double getPseudorangeRateCarrierUncertaintyInMetersPerSec() {
- return mPseudorangeRateCarrierUncertaintyInMetersPerSec;
- }
-
- /**
- * Sets 1-Sigma uncertainty of the pseudorange rate carrier.
- */
- public void setPseudorangeRateCarrierUncertaintyInMetersPerSec(double value) {
- mPseudorangeRateCarrierUncertaintyInMetersPerSec = value;
- }
-
public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
@Override
public GnssMeasurement createFromParcel(Parcel parcel) {
@@ -1211,10 +1247,11 @@
gnssMeasurement.mFlags = parcel.readInt();
gnssMeasurement.mSvid = (short) parcel.readInt();
+ gnssMeasurement.mConstellationType = parcel.readByte();
gnssMeasurement.mTimeOffsetInNs = parcel.readDouble();
gnssMeasurement.mState = (short) parcel.readInt();
- gnssMeasurement.mReceivedGpsTowInNs = parcel.readLong();
- gnssMeasurement.mReceivedGpsTowUncertaintyInNs = parcel.readLong();
+ gnssMeasurement.mReceivedSvTimeInNs = parcel.readLong();
+ gnssMeasurement.mReceivedSvTimeUncertaintyInNs = parcel.readLong();
gnssMeasurement.mCn0InDbHz = parcel.readDouble();
gnssMeasurement.mPseudorangeRateInMetersPerSec = parcel.readDouble();
gnssMeasurement.mPseudorangeRateUncertaintyInMetersPerSec = parcel.readDouble();
@@ -1241,8 +1278,6 @@
gnssMeasurement.mAzimuthInDeg = parcel.readDouble();
gnssMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble();
gnssMeasurement.mUsedInFix = parcel.readInt() != 0;
- gnssMeasurement.mPseudorangeRateCarrierInMetersPerSec = parcel.readDouble();
- gnssMeasurement.mPseudorangeRateCarrierUncertaintyInMetersPerSec = parcel.readDouble();
return gnssMeasurement;
}
@@ -1257,10 +1292,11 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mFlags);
parcel.writeInt(mSvid);
+ parcel.writeByte(mConstellationType);
parcel.writeDouble(mTimeOffsetInNs);
parcel.writeInt(mState);
- parcel.writeLong(mReceivedGpsTowInNs);
- parcel.writeLong(mReceivedGpsTowUncertaintyInNs);
+ parcel.writeLong(mReceivedSvTimeInNs);
+ parcel.writeLong(mReceivedSvTimeUncertaintyInNs);
parcel.writeDouble(mCn0InDbHz);
parcel.writeDouble(mPseudorangeRateInMetersPerSec);
parcel.writeDouble(mPseudorangeRateUncertaintyInMetersPerSec);
@@ -1287,8 +1323,6 @@
parcel.writeDouble(mAzimuthInDeg);
parcel.writeDouble(mAzimuthUncertaintyInDeg);
parcel.writeInt(mUsedInFix ? 1 : 0);
- parcel.writeDouble(mPseudorangeRateCarrierInMetersPerSec);
- parcel.writeDouble(mPseudorangeRateCarrierUncertaintyInMetersPerSec);
}
@Override
@@ -1303,17 +1337,17 @@
StringBuilder builder = new StringBuilder("GnssMeasurement:\n");
builder.append(String.format(format, "Svid", mSvid));
-
+ builder.append(String.format(format, "ConstellationType", mConstellationType));
builder.append(String.format(format, "TimeOffsetInNs", mTimeOffsetInNs));
builder.append(String.format(format, "State", getStateString()));
builder.append(String.format(
formatWithUncertainty,
- "ReceivedGpsTowInNs",
- mReceivedGpsTowInNs,
- "ReceivedGpsTowUncertaintyInNs",
- mReceivedGpsTowUncertaintyInNs));
+ "ReceivedSvTimeInNs",
+ mReceivedSvTimeInNs,
+ "ReceivedSvTimeUncertaintyInNs",
+ mReceivedSvTimeUncertaintyInNs));
builder.append(String.format(format, "Cn0InDbHz", mCn0InDbHz));
@@ -1413,11 +1447,6 @@
builder.append(String.format(format, "UsedInFix", mUsedInFix));
- builder.append(String.format(format, "PseudorangeRateCarrierInMetersPerSec",
- mPseudorangeRateCarrierInMetersPerSec));
- builder.append(String.format(format, "PseudorangeRateCarrierUncertaintyInMetersPerSec",
- mPseudorangeRateCarrierUncertaintyInMetersPerSec));
-
return builder.toString();
}
@@ -1426,8 +1455,8 @@
setSvid((short) 0);
setTimeOffsetInNs(Long.MIN_VALUE);
setState(STATE_UNKNOWN);
- setReceivedGpsTowInNs(Long.MIN_VALUE);
- setReceivedGpsTowUncertaintyInNs(Long.MAX_VALUE);
+ setReceivedSvTimeInNs(Long.MIN_VALUE);
+ setReceivedSvTimeUncertaintyInNs(Long.MAX_VALUE);
setCn0InDbHz(Double.MIN_VALUE);
setPseudorangeRateInMetersPerSec(Double.MIN_VALUE);
setPseudorangeRateUncertaintyInMetersPerSec(Double.MIN_VALUE);
@@ -1454,8 +1483,6 @@
resetAzimuthInDeg();
resetAzimuthUncertaintyInDeg();
setUsedInFix(false);
- setPseudorangeRateCarrierInMetersPerSec(Double.MIN_VALUE);
- setPseudorangeRateCarrierUncertaintyInMetersPerSec(Double.MIN_VALUE);
}
private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssNavigationMessage.java b/location/java/android/location/GnssNavigationMessage.java
index 86328eb..faefd0bb 100644
--- a/location/java/android/location/GnssNavigationMessage.java
+++ b/location/java/android/location/GnssNavigationMessage.java
@@ -34,36 +34,33 @@
/** The type of the GPS Clock. */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_L1CA, MESSAGE_TYPE_L2CNAV, MESSAGE_TYPE_L5CNAV,
- MESSAGE_TYPE_CNAV2})
+ @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_GPS_L1CA, MESSAGE_TYPE_GPS_L2CNAV,
+ MESSAGE_TYPE_GPS_L5CNAV, MESSAGE_TYPE_GPS_CNAV2, MESSAGE_TYPE_GLO_L1CA, MESSAGE_TYPE_BDS_D1,
+ MESSAGE_TYPE_BDS_D2, MESSAGE_TYPE_GAL_I, MESSAGE_TYPE_GAL_F})
public @interface GnssNavigationMessageType {}
// The following enumerations must be in sync with the values declared in gps.h
- /**
- * The type of the navigation message is not available or unknown.
- */
- public static final byte MESSAGE_TYPE_UNKNOWN = 0;
-
- /**
- * The Navigation Message is of type L1 C/A.
- */
- public static final byte MESSAGE_TYPE_L1CA = 1;
-
- /**
- * The Navigation Message is of type L1-CNAV.
- */
- public static final byte MESSAGE_TYPE_L2CNAV = 2;
-
- /**
- * The Navigation Message is of type L5-CNAV.
- */
- public static final byte MESSAGE_TYPE_L5CNAV = 3;
-
- /**
- * The Navigation Message is of type CNAV-2.
- */
- public static final byte MESSAGE_TYPE_CNAV2 = 4;
+ /** Message type unknown */
+ public static final short MESSAGE_TYPE_UNKNOWN = 0;
+ /** GPS L1 C/A message contained in the structure. */
+ public static final short MESSAGE_TYPE_GPS_L1CA = 0x0101;
+ /** GPS L2-CNAV message contained in the structure. */
+ public static final short MESSAGE_TYPE_GPS_L2CNAV = 0x0102;
+ /** GPS L5-CNAV message contained in the structure. */
+ public static final short MESSAGE_TYPE_GPS_L5CNAV = 0x0103;
+ /** GPS CNAV-2 message contained in the structure. */
+ public static final short MESSAGE_TYPE_GPS_CNAV2 = 0x0104;
+ /** Glonass L1 CA message contained in the structure. */
+ public static final short MESSAGE_TYPE_GLO_L1CA = 0x0301;
+ /** Beidou D1 message contained in the structure. */
+ public static final short MESSAGE_TYPE_BDS_D1 = 0x0501;
+ /** Beidou D2 message contained in the structure. */
+ public static final short MESSAGE_TYPE_BDS_D2 = 0x0502;
+ /** Galileo I/NAV message contained in the structure. */
+ public static final short MESSAGE_TYPE_GAL_I = 0x0601;
+ /** Galileo F/NAV message contained in the structure. */
+ public static final short MESSAGE_TYPE_GAL_F = 0x0602;
/**
* The Navigation Message Status is 'unknown'.
@@ -83,7 +80,7 @@
// End enumerations in sync with gps.h
- private byte mType;
+ private short mType;
private short mSvid;
private short mMessageId;
private short mSubmessageId;
@@ -117,14 +114,14 @@
* Gets the type of the navigation message contained in the object.
*/
@GnssNavigationMessageType
- public byte getType() {
+ public short getType() {
return mType;
}
/**
* Sets the type of the navigation message.
*/
- public void setType(@GnssNavigationMessageType byte value) {
+ public void setType(@GnssNavigationMessageType short value) {
mType = value;
}
@@ -136,14 +133,24 @@
switch (mType) {
case MESSAGE_TYPE_UNKNOWN:
return "Unknown";
- case MESSAGE_TYPE_L1CA:
- return "L1 C/A";
- case MESSAGE_TYPE_L2CNAV:
- return "L2-CNAV";
- case MESSAGE_TYPE_L5CNAV:
- return "L5-CNAV";
- case MESSAGE_TYPE_CNAV2:
- return "CNAV-2";
+ case MESSAGE_TYPE_GPS_L1CA:
+ return "GPS L1 C/A";
+ case MESSAGE_TYPE_GPS_L2CNAV:
+ return "GPS L2-CNAV";
+ case MESSAGE_TYPE_GPS_L5CNAV:
+ return "GPS L5-CNAV";
+ case MESSAGE_TYPE_GPS_CNAV2:
+ return "GPS CNAV2";
+ case MESSAGE_TYPE_GLO_L1CA:
+ return "Glonass L1 C/A";
+ case MESSAGE_TYPE_BDS_D1:
+ return "Beidou D1";
+ case MESSAGE_TYPE_BDS_D2:
+ return "Beidou D2";
+ case MESSAGE_TYPE_GAL_I:
+ return "Galileo I";
+ case MESSAGE_TYPE_GAL_F:
+ return "Galileo F";
default:
return "<Invalid:" + mType + ">";
}
@@ -255,7 +262,7 @@
public GnssNavigationMessage createFromParcel(Parcel parcel) {
GnssNavigationMessage navigationMessage = new GnssNavigationMessage();
- navigationMessage.setType(parcel.readByte());
+ navigationMessage.setType((short) parcel.readInt());
navigationMessage.setSvid((short) parcel.readInt());
navigationMessage.setMessageId((short) parcel.readInt());
navigationMessage.setSubmessageId((short) parcel.readInt());
@@ -283,7 +290,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeByte(mType);
+ parcel.writeInt(mType);
parcel.writeInt(mSvid);
parcel.writeInt(mMessageId);
parcel.writeInt(mSubmessageId);
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 906e944..06ce30c 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -16,25 +16,36 @@
package android.location;
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class represents the current state of the GNSS engine.
* This class is used in conjunction with the {@link GnssStatusCallback}.
*/
public final class GnssStatus {
/** Unknown constellation type. */
- public static final int CONSTELLATION_UNKNOWN = 0;
+ public static final byte CONSTELLATION_UNKNOWN = 0;
/** Constellation type constant for GPS. */
- public static final int CONSTELLATION_GPS = 1;
+ public static final byte CONSTELLATION_GPS = 1;
/** Constellation type constant for SBAS. */
- public static final int CONSTELLATION_SBAS = 2;
+ public static final byte CONSTELLATION_SBAS = 2;
/** Constellation type constant for Glonass. */
- public static final int CONSTELLATION_GLONASS = 3;
+ public static final byte CONSTELLATION_GLONASS = 3;
/** Constellation type constant for QZSS. */
- public static final int CONSTELLATION_QZSS = 4;
+ public static final byte CONSTELLATION_QZSS = 4;
/** Constellation type constant for Beidou. */
- public static final int CONSTELLATION_BEIDOU = 5;
+ public static final byte CONSTELLATION_BEIDOU = 5;
/** Constellation type constant for Galileo. */
- public static final int CONSTELLATION_GALILEO = 6;
+ public static final byte CONSTELLATION_GALILEO = 6;
+
+ /** Constellation type. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({CONSTELLATION_UNKNOWN, CONSTELLATION_GPS, CONSTELLATION_SBAS, CONSTELLATION_GLONASS,
+ CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO})
+ public @interface ConstellationType {}
// these must match the definitions in gps.h
/** @hide */
@@ -80,9 +91,10 @@
* Retrieves the constellation type of the satellite at the specified position.
* @param satIndex the index of the satellite in the list.
*/
- public int getConstellationType(int satIndex) {
- return (mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
- & CONSTELLATION_TYPE_MASK;
+ @ConstellationType
+ public byte getConstellationType(int satIndex) {
+ return (byte) ((mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
+ & CONSTELLATION_TYPE_MASK);
}
/**
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index e41e20c..7b3dd7d 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -147,7 +147,6 @@
& GnssStatus.CONSTELLATION_TYPE_MASK;
// Skip all non-GPS satellites.
if (constellationType != GnssStatus.CONSTELLATION_GPS) {
- // TODO: translate the defacto pre-N use of prn's >32 to new struct
continue;
}
int prn = svidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH;
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 4f1e039..bc8b0262 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -69,7 +69,7 @@
in String packageName);
void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
- int getGpsYearOfHardware();
+ int getGnssYearOfHardware();
// --- deprecated ---
List<String> getAllProviders();
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 23f0710..e14e36d 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1959,11 +1959,11 @@
* @hide
*/
@TestApi
- public int getGpsYearOfHardware() {
+ public int getGnssYearOfHardware() {
try {
- return mService.getGpsYearOfHardware();
+ return mService.getGnssYearOfHardware();
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getGpsSystemInfo: ", e);
+ Log.e(TAG, "RemoteException in getGnssSystemInfo: ", e);
return 0;
}
}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index d06da97..646ab4e 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -65,6 +65,7 @@
* <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
* <tr><td>{@link #KEY_CHANNEL_COUNT}</td><td>Integer</td><td></td></tr>
* <tr><td>{@link #KEY_SAMPLE_RATE}</td><td>Integer</td><td></td></tr>
+ * <tr><td>{@link #KEY_PCM_ENCODING}</td><td>Integer</td><td>optional</td></tr>
* <tr><td>{@link #KEY_IS_ADTS}</td><td>Integer</td><td>optional, if <em>decoding</em> AAC audio content, setting this key to 1 indicates that each audio frame is prefixed by the ADTS header.</td></tr>
* <tr><td>{@link #KEY_AAC_PROFILE}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is AAC audio, specifies the desired profile.</td></tr>
* <tr><td>{@link #KEY_AAC_SBR_MODE}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is AAC audio, specifies the desired SBR mode.</td></tr>
@@ -197,6 +198,26 @@
public static final String KEY_FRAME_RATE = "frame-rate";
/**
+ * A key describing the raw audio sample encoding/format.
+ *
+ * <p>The associated value is an integer, using one of the
+ * {@link AudioFormat}.ENCODING_PCM_ values.</p>
+ *
+ * <p>This is an optional key for audio decoders and encoders specifying the
+ * desired raw audio sample format during {@link MediaCodec#configure
+ * MediaCodec.configure(…)} call. Use {@link MediaCodec#getInputFormat
+ * MediaCodec.getInput}/{@link MediaCodec#getOutputFormat OutputFormat(…)}
+ * to confirm the actual format. For the PCM decoder this key specifies both
+ * input and output sample encodings.</p>
+ *
+ * <p>This key is also used by {@link MediaExtractor} to specify the sample
+ * format of audio data, if it is specified.</p>
+ *
+ * <p>If this key is missing, the raw audio sample format is signed 16-bit short.</p>
+ */
+ public static final String KEY_PCM_ENCODING = "pcm-encoding";
+
+ /**
* A key describing the capture rate of a video format in frames/sec.
* <p>
* When capture rate is different than the frame rate, it means that the
@@ -564,7 +585,7 @@
public static final String KEY_IS_TIMED_TEXT = "is-timed-text";
// The following color aspect values must be in sync with the ones in HardwareAPI.h.
- /*
+ /**
* An optional key describing the color primaries, white point and
* luminance factors for video content.
*
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index adb6b06..893bd3c 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -29,6 +29,10 @@
void onMediaButton(in Intent mediaButtonIntent, int sequenceNumber, in ResultReceiver cb);
// These callbacks are for the TransportPerformer
+ void onPrepare();
+ void onPrepareFromMediaId(String mediaId, in Bundle extras);
+ void onPrepareFromSearch(String query, in Bundle extras);
+ void onPrepareFromUri(in Uri uri, in Bundle extras);
void onPlay();
void onPlayFromMediaId(String mediaId, in Bundle extras);
void onPlayFromSearch(String query, in Bundle extras);
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 285e5f7..249bcdc 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -50,6 +50,10 @@
void setVolumeTo(int value, int flags, String packageName);
// These commands are for the TransportControls
+ void prepare();
+ void prepareFromMediaId(String mediaId, in Bundle extras);
+ void prepareFromSearch(String string, in Bundle extras);
+ void prepareFromUri(in Uri uri, in Bundle extras);
void play();
void playFromMediaId(String mediaId, in Bundle extras);
void playFromSearch(String string, in Bundle extras);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 3d9b60d..13db00e 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -592,6 +592,90 @@
}
/**
+ * Request that the player prepare its playback. Once the preparation is done, the session
+ * will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
+ * {@link #play} can be called to start playback. If the preparation is not needed,
+ * {@link #play} can be directly called without this method.
+ */
+ public void prepare() {
+ try {
+ mSessionBinder.prepare();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling prepare.", e);
+ }
+ }
+
+ /**
+ * Request that the player prepare playback for a specific media id. Once the preparation is
+ * done, the session will change its playback state to {@link PlaybackState#STATE_PAUSED}.
+ * Afterwards, {@link #play} can be called to start playback. If the preparation is not
+ * needed, {@link #playFromMediaId} can be directly called without this method.
+ *
+ * @param mediaId The id of the requested media.
+ * @param extras Optional extras that can include extra information about the media item
+ * to be prepared.
+ */
+ public void prepareFromMediaId(String mediaId, Bundle extras) {
+ if (TextUtils.isEmpty(mediaId)) {
+ throw new IllegalArgumentException(
+ "You must specify a non-empty String for prepareFromMediaId.");
+ }
+ try {
+ mSessionBinder.prepareFromMediaId(mediaId, extras);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
+ }
+ }
+
+ /**
+ * Request that the player prepare playback for a specific search query.
+ * An empty or null query should be treated as a request to prepare any
+ * music. Once the preparation is done, the session will change its playback state to
+ * {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to start
+ * playback. If the preparation is not needed, {@link #playFromSearch} can be directly
+ * called without this method.
+ *
+ * @param query The search query.
+ * @param extras Optional extras that can include extra information
+ * about the query.
+ */
+ public void prepareFromSearch(String query, Bundle extras) {
+ if (query == null) {
+ // This is to remain compatible with
+ // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
+ query = "";
+ }
+ try {
+ mSessionBinder.prepareFromSearch(query, extras);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
+ }
+ }
+
+ /**
+ * Request that the player prepare playback for a specific {@link Uri}.
+ * Once the preparation is done, the session will change its playback state to
+ * {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to start
+ * playback. If the preparation is not needed, {@link #playFromUri} can be directly
+ * called without this method.
+ *
+ * @param uri The URI of the requested media.
+ * @param extras Optional extras that can include extra information about the media item
+ * to be prepared.
+ */
+ public void prepareFromUri(Uri uri, Bundle extras) {
+ if (uri == null || Uri.EMPTY.equals(uri)) {
+ throw new IllegalArgumentException(
+ "You must specify a non-empty Uri for prepareFromUri.");
+ }
+ try {
+ mSessionBinder.prepareFromUri(uri, extras);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
+ }
+ }
+
+ /**
* Request that the player start its playback at its current position.
*/
public void play() {
@@ -605,7 +689,6 @@
/**
* Request that the player start playback for a specific media id.
*
- * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param mediaId The id of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
@@ -627,10 +710,9 @@
* An empty or null query should be treated as a request to play any
* music.
*
- * @see PlaybackState#EXTRA_PREPARE_ONLY
* @param query The search query.
* @param extras Optional extras that can include extra information
- * about the query.
+ * about the query.
*/
public void playFromSearch(String query, Bundle extras) {
if (query == null) {
@@ -648,8 +730,7 @@
/**
* Request that the player start playback for a specific {@link Uri}.
*
- * @see PlaybackState#EXTRA_PREPARE_ONLY
- * @param uri The URI of the requested media.
+ * @param uri The URI of the requested media.
* @param extras Optional extras that can include extra information about the media item
* to be played.
*/
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 8c5b19c..3b1b6c8 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -87,12 +87,6 @@
public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
/**
- * Set this flag on the session to indicate that it can handle
- * the {@link PlaybackState#EXTRA_PREPARE_ONLY} field.
- */
- public static final int FLAG_HANDLES_PREPARE_ONLY = 1 << 2;
-
- /**
* System only flag for a session that needs to have priority over all other
* sessions. This flag ensures this session will receive media button events
* regardless of the current ordering in the system.
@@ -106,7 +100,6 @@
@IntDef(flag = true, value = {
FLAG_HANDLES_MEDIA_BUTTONS,
FLAG_HANDLES_TRANSPORT_CONTROLS,
- FLAG_HANDLES_PREPARE_ONLY,
FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
public @interface SessionFlags { }
@@ -519,6 +512,22 @@
}
}
+ private void dispatchPrepare() {
+ postToCallback(CallbackMessageHandler.MSG_PREPARE);
+ }
+
+ private void dispatchPrepareFromMediaId(String mediaId, Bundle extras) {
+ postToCallback(CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
+ }
+
+ private void dispatchPrepareFromSearch(String query, Bundle extras) {
+ postToCallback(CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
+ }
+
+ private void dispatchPrepareFromUri(Uri uri, Bundle extras) {
+ postToCallback(CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
+ }
+
private void dispatchPlay() {
postToCallback(CallbackMessageHandler.MSG_PLAY);
}
@@ -805,16 +814,49 @@
}
/**
- * Override to handle requests to begin playback.
+ * Override to handle requests to prepare playback. The state of playback should be updated
+ * to {@link PlaybackState#STATE_PAUSED} after the preparation is done. Override
+ * {@link #onPlay} to handle requests for starting playback of prepared content.
*/
- public void onPlay() {
+ public void onPrepare() {
}
/**
- * Override to handle requests to play a specific mediaId that was
- * provided by your app's {@link MediaBrowserService}.
+ * Override to handle requests to prepare for playing a specific mediaId that was provided
+ * by your app's {@link MediaBrowserService}. The state of playback should be updated
+ * to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback of
+ * the prepared content should start in the implementation of {@link #onPlay}. Override
+ * {@link #onPlayFromMediaId} to handle requests for starting playback without preparation.
*/
- public void onPlayFromMediaId(String mediaId, Bundle extras) {
+ public void onPrepareFromMediaId(String mediaId, Bundle extras) {
+ }
+
+ /**
+ * Override to handle requests to prepare playback from a search query. An
+ * empty query indicates that the app may prepare any music. The
+ * implementation should attempt to make a smart choice about what to
+ * play. The state of playback should be updated to {@link PlaybackState#STATE_PAUSED}
+ * after the preparation is done. The playback of the prepared content should start
+ * in the implementation of {@link #onPlay}. Override {@link #onPlayFromSearch}
+ * to handle requests for starting playback without preparation.
+ */
+ public void onPrepareFromSearch(String query, Bundle extras) {
+ }
+
+ /**
+ * Override to handle requests to prepare a specific media item represented by a URI.
+ * The state of playback should be updated to {@link PlaybackState#STATE_PAUSED}
+ * after the preparation is done. The playback of the prepared content should start in
+ * the implementation of {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
+ * for starting playback without preparation.
+ */
+ public void onPrepareFromUri(Uri uri, Bundle extras) {
+ }
+
+ /**
+ * Override to handle requests to begin playback.
+ */
+ public void onPlay() {
}
/**
@@ -827,6 +869,13 @@
}
/**
+ * Override to handle requests to play a specific mediaId that was
+ * provided by your app's {@link MediaBrowserService}.
+ */
+ public void onPlayFromMediaId(String mediaId, Bundle extras) {
+ }
+
+ /**
* Override to handle requests to play a specific media item represented by a URI.
*/
public void onPlayFromUri(Uri uri, Bundle extras) {
@@ -937,6 +986,38 @@
}
@Override
+ public void onPrepare() {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPrepare();
+ }
+ }
+
+ @Override
+ public void onPrepareFromMediaId(String mediaId, Bundle extras) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPrepareFromMediaId(mediaId, extras);
+ }
+ }
+
+ @Override
+ public void onPrepareFromSearch(String query, Bundle extras) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPrepareFromSearch(query, extras);
+ }
+ }
+
+ @Override
+ public void onPrepareFromUri(Uri uri, Bundle extras) {
+ MediaSession session = mMediaSession.get();
+ if (session != null) {
+ session.dispatchPrepareFromUri(uri, extras);
+ }
+ }
+
+ @Override
public void onPlay() {
MediaSession session = mMediaSession.get();
if (session != null) {
@@ -1162,24 +1243,28 @@
private class CallbackMessageHandler extends Handler {
- private static final int MSG_PLAY = 1;
- private static final int MSG_PLAY_MEDIA_ID = 2;
- private static final int MSG_PLAY_SEARCH = 3;
- private static final int MSG_SKIP_TO_ITEM = 4;
- private static final int MSG_PAUSE = 5;
- private static final int MSG_STOP = 6;
- private static final int MSG_NEXT = 7;
- private static final int MSG_PREVIOUS = 8;
- private static final int MSG_FAST_FORWARD = 9;
- private static final int MSG_REWIND = 10;
- private static final int MSG_SEEK_TO = 11;
- private static final int MSG_RATE = 12;
- private static final int MSG_CUSTOM_ACTION = 13;
- private static final int MSG_MEDIA_BUTTON = 14;
- private static final int MSG_COMMAND = 15;
- private static final int MSG_ADJUST_VOLUME = 16;
- private static final int MSG_SET_VOLUME = 17;
- private static final int MSG_PLAY_URI = 18;
+ private static final int MSG_COMMAND = 1;
+ private static final int MSG_MEDIA_BUTTON = 2;
+ private static final int MSG_PREPARE = 3;
+ private static final int MSG_PREPARE_MEDIA_ID = 4;
+ private static final int MSG_PREPARE_SEARCH = 5;
+ private static final int MSG_PREPARE_URI = 6;
+ private static final int MSG_PLAY = 7;
+ private static final int MSG_PLAY_MEDIA_ID = 8;
+ private static final int MSG_PLAY_SEARCH = 9;
+ private static final int MSG_PLAY_URI = 10;
+ private static final int MSG_SKIP_TO_ITEM = 11;
+ private static final int MSG_PAUSE = 12;
+ private static final int MSG_STOP = 13;
+ private static final int MSG_NEXT = 14;
+ private static final int MSG_PREVIOUS = 15;
+ private static final int MSG_FAST_FORWARD = 16;
+ private static final int MSG_REWIND = 17;
+ private static final int MSG_SEEK_TO = 18;
+ private static final int MSG_RATE = 19;
+ private static final int MSG_CUSTOM_ACTION = 20;
+ private static final int MSG_ADJUST_VOLUME = 21;
+ private static final int MSG_SET_VOLUME = 22;
private MediaSession.Callback mCallback;
@@ -1210,6 +1295,25 @@
public void handleMessage(Message msg) {
VolumeProvider vp;
switch (msg.what) {
+ case MSG_COMMAND:
+ Command cmd = (Command) msg.obj;
+ mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
+ break;
+ case MSG_MEDIA_BUTTON:
+ mCallback.onMediaButtonEvent((Intent) msg.obj);
+ break;
+ case MSG_PREPARE:
+ mCallback.onPrepare();
+ break;
+ case MSG_PREPARE_MEDIA_ID:
+ mCallback.onPrepareFromMediaId((String) msg.obj, msg.getData());
+ break;
+ case MSG_PREPARE_SEARCH:
+ mCallback.onPrepareFromSearch((String) msg.obj, msg.getData());
+ break;
+ case MSG_PREPARE_URI:
+ mCallback.onPrepareFromUri((Uri) msg.obj, msg.getData());
+ break;
case MSG_PLAY:
mCallback.onPlay();
break;
@@ -1252,13 +1356,6 @@
case MSG_CUSTOM_ACTION:
mCallback.onCustomAction((String) msg.obj, msg.getData());
break;
- case MSG_MEDIA_BUTTON:
- mCallback.onMediaButtonEvent((Intent) msg.obj);
- break;
- case MSG_COMMAND:
- Command cmd = (Command) msg.obj;
- mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
- break;
case MSG_ADJUST_VOLUME:
synchronized (mLock) {
vp = mVolumeProvider;
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 1079a1f..1485cd7 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -133,19 +133,32 @@
public static final long ACTION_PLAY_FROM_URI = 1 << 13;
/**
- * Used as an optional boolean extra field in
- * {@link MediaController.TransportControls#playFromMediaId},
- * {@link MediaController.TransportControls#playFromSearch}, and
- * {@link MediaController.TransportControls#playFromUri}. Value of {@code true} overrides
- * the default behavior of starting the playback after preparing. Check
- * {@link MediaSession#FLAG_HANDLES_PREPARE_ONLY} to see if the media session supports this.
+ * Indicates this session supports the prepare command.
*
- * @see MediaSession#FLAG_HANDLES_PREPARE_ONLY
- * @see MediaController.TransportControls#playFromMediaId
- * @see MediaController.TransportControls#playFromSearch
- * @see MediaController.TransportControls#playFromUri
+ * @see Builder#setActions(long)
*/
- public static final String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
+ public static final long ACTION_PREPARE = 1 << 14;
+
+ /**
+ * Indicates this session supports the prepare from media id command.
+ *
+ * @see Builder#setActions(long)
+ */
+ public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15;
+
+ /**
+ * Indicates this session supports the prepare from search command.
+ *
+ * @see Builder#setActions(long)
+ */
+ public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16;
+
+ /**
+ * Indicates this session supports the prepare from URI command.
+ *
+ * @see Builder#setActions(long)
+ */
+ public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
/**
* This is the default playback state and indicates that no media has been
@@ -330,6 +343,10 @@
* <li> {@link PlaybackState#STATE_REWINDING}</li>
* <li> {@link PlaybackState#STATE_BUFFERING}</li>
* <li> {@link PlaybackState#STATE_ERROR}</li>
+ * <li> {@link PlaybackState#STATE_CONNECTING}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
* </ul>
*/
public int getState() {
@@ -380,6 +397,10 @@
* <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
* <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
* <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
* </ul>
*/
public long getActions() {
@@ -831,6 +852,10 @@
* <li> {@link PlaybackState#STATE_REWINDING}</li>
* <li> {@link PlaybackState#STATE_BUFFERING}</li>
* <li> {@link PlaybackState#STATE_ERROR}</li>
+ * <li> {@link PlaybackState#STATE_CONNECTING}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
* </ul>
*
* @param state The current state of playback.
@@ -870,6 +895,10 @@
* <li> {@link PlaybackState#STATE_REWINDING}</li>
* <li> {@link PlaybackState#STATE_BUFFERING}</li>
* <li> {@link PlaybackState#STATE_ERROR}</li>
+ * <li> {@link PlaybackState#STATE_CONNECTING}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
+ * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
* </ul>
*
* @param state The current state of playback.
@@ -900,6 +929,10 @@
* <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
* <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
* <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
+ * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
* </ul>
*
* @param actions The set of actions allowed.
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 9203ef2..1c11842 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1314,6 +1314,8 @@
private static final char COMMA = ',';
private static final String DELIMITER = ",";
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
private Genres() {}
/**
@@ -1359,6 +1361,12 @@
* @return genre strings.
*/
public static String[] decode(String genres) {
+ if (genres.isEmpty()) {
+ return EMPTY_STRING_ARRAY;
+ }
+ if (genres.indexOf(COMMA) == -1 && genres.indexOf(DOUBLE_QUOTE) == -1) {
+ return new String[] {genres.trim()};
+ }
StringBuilder sb = new StringBuilder();
List<String> results = new ArrayList<>();
int length = genres.length();
@@ -1394,13 +1402,11 @@
}
/**
- * Check whether a given genre is canonical or not.
+ * Returns whether a given text is a canonical genre defined in {@link Genres}.
*
* @param genre The name of genre to be checked.
* @return {@code true} if the genre is canonical, otherwise {@code false}.
- * @hide
*/
- @SystemApi
public static boolean isCanonical(String genre) {
return CANONICAL_GENRES.contains(genre);
}
diff --git a/packages/DocumentsUI/res/layout/drawer_layout.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml
index e3def05..065102b 100644
--- a/packages/DocumentsUI/res/layout/drawer_layout.xml
+++ b/packages/DocumentsUI/res/layout/drawer_layout.xml
@@ -61,7 +61,7 @@
android:layout_gravity="start"
android:orientation="vertical"
android:elevation="16dp"
- android:background="@color/window_background">
+ android:background="@color/drawer_background">
<Toolbar
android:id="@+id/roots_toolbar"
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 0d336f9..03c6a83 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -17,7 +17,7 @@
<com.android.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/window_background"
+ android:background="@color/directory_background"
android:outlineProvider="bounds"
android:elevation="4dp"
android:orientation="vertical">
@@ -45,7 +45,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:background="@color/window_background"
+ android:background="@color/directory_background"
android:focusable="true"
android:focusableInTouchMode="true"
android:visibility="gone">
diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml
index b0331be..d866145 100644
--- a/packages/DocumentsUI/res/layout/item_dir_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml
@@ -20,7 +20,7 @@
android:layout_height="wrap_content"
android:layout_margin="@dimen/grid_item_margin"
android:background="@color/item_doc_background"
- android:elevation="5dp"
+ android:elevation="@dimen/grid_item_elevation"
android:focusable="true" >
<LinearLayout
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index dd02d1c..1890f2f 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -19,7 +19,7 @@
android:layout_height="wrap_content"
android:layout_margin="@dimen/grid_item_margin"
android:background="@color/item_doc_background"
- android:elevation="5dp"
+ android:elevation="@dimen/grid_item_elevation"
android:focusable="true">
<!-- Main item thumbnail. Comprised of two overlapping images, the
diff --git a/packages/DocumentsUI/res/values-ldrtl/dimens.xml b/packages/DocumentsUI/res/values-ldrtl/config.xml
similarity index 100%
rename from packages/DocumentsUI/res/values-ldrtl/dimens.xml
rename to packages/DocumentsUI/res/values-ldrtl/config.xml
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/config.xml b/packages/DocumentsUI/res/values-sw720dp-land/config.xml
new file mode 100644
index 0000000..8d9526d
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp-land/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <bool name="always_show_summary">true</bool>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
index c9dee8d..fa11244 100644
--- a/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp-land/dimens.xml
@@ -15,8 +15,6 @@
-->
<resources>
- <bool name="always_show_summary">true</bool>
-
<dimen name="list_item_height">64dp</dimen>
<dimen name="list_item_padding">24dp</dimen>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index c868d34..3785adf 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -21,18 +21,18 @@
else that needs to manually declare a background matching the "default"
app background (e.g. the drawer overlay). -->
<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>
<color name="primary">@*android:color/material_blue_grey_900</color>
<color name="accent">@*android:color/accent_material_light</color>
+ <color name="accent_dark">@*android:color/accent_material_dark</color>
<color name="action_mode">@color/material_grey_400</color>
<color name="band_select_background">#88ffffff</color>
<color name="band_select_border">#44000000</color>
-
- <color name="item_doc_background">#fffafafa</color>
- <color name="item_doc_background_selected">#ffe0f2f1</color>
-
- <color name="menu_search_background">#ff676f74</color>
-
</resources>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index e8d8c8eb..07498a0 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -20,4 +20,6 @@
<!-- Intentionally unset. Vendors should set this in an overlay. -->
<string name="trusted_quick_viewer_package"></string>
+ <bool name="list_divider_inset_left">true</bool>
+ <bool name="always_show_summary">false</bool>
</resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index 5adb165..9fc8a73 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -17,37 +17,24 @@
<resources>
<dimen name="grid_container_padding">10dp</dimen>
<dimen name="list_container_padding">0dp</dimen>
-
<dimen name="icon_size">40dp</dimen>
<dimen name="root_icon_size">24dp</dimen>
<dimen name="root_icon_margin">0dp</dimen>
<dimen name="check_icon_size">30dp</dimen>
-
<dimen name="list_item_thumbnail_size">40dp</dimen>
<dimen name="grid_item_icon_size">30dp</dimen>
-
<dimen name="progress_bar_height">4dp</dimen>
-
<dimen name="grid_width">152dp</dimen>
<dimen name="grid_height">176dp</dimen>
-
<dimen name="grid_item_width">152dp</dimen>
<dimen name="grid_item_height">176dp</dimen>
<dimen name="grid_item_margin">4dp</dimen>
-
<dimen name="grid_padding_horiz">4dp</dimen>
<dimen name="grid_padding_vert">4dp</dimen>
-
<dimen name="list_item_height">72dp</dimen>
<dimen name="list_item_padding">16dp</dimen>
-
<dimen name="list_divider_inset">72dp</dimen>
- <bool name="list_divider_inset_left">true</bool>
-
- <bool name="always_show_summary">false</bool>
-
<dimen name="dir_elevation">8dp</dimen>
-
<dimen name="drag_shadow_size">120dp</dimen>
-
+ <dimen name="grid_item_elevation">2dp</dimen>
</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 648c79e..b67a6915 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -284,7 +284,7 @@
if (dir != null) {
dir.pasteFromClipboard();
}
- return true;
+ return true;
case R.id.menu_advanced:
setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this));
@@ -456,7 +456,7 @@
DirectoryFragment dir = getDirectoryFragment();
if (dir != null) {
dir.onSortOrderChanged();
- };
+ }
}
/**
@@ -473,7 +473,7 @@
DirectoryFragment dir = getDirectoryFragment();
if (dir != null) {
dir.onViewModeChanged();
- };
+ }
}
public void setPending(boolean pending) {
@@ -561,9 +561,7 @@
}
}
- if (size > 1) {
- mState.stack.pop();
- refreshCurrentRootAndDirectory(ANIM_LEAVE);
+ if (popDir()) {
return;
}
@@ -603,8 +601,12 @@
return true;
}
} else if (keyCode == KeyEvent.KEYCODE_TAB) {
+ // Tab toggles focus on the navigation drawer.
toggleNavDrawerFocus();
return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DEL) {
+ popDir();
+ return true;
}
return super.onKeyDown(keyCode, event);
}
@@ -641,6 +643,21 @@
}
}
+ /**
+ * Pops the top entry off the directory stack, and returns the user to the previous directory.
+ * If the directory stack only contains one item, this method does nothing.
+ *
+ * @return Whether the stack was popped.
+ */
+ private boolean popDir() {
+ if (mState.stack.size() > 1) {
+ mState.stack.pop();
+ refreshCurrentRootAndDirectory(ANIM_LEAVE);
+ return true;
+ }
+ return false;
+ }
+
private static final class PickRootTask extends PairedTask<BaseActivity, Void, DocumentInfo> {
private RootInfo mRoot;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
index 172282a..699605f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -64,23 +64,23 @@
// Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
// root that is not explicitly recognized by the Metrics code (see {@link
- // #getSanitizedRootIndex}). Apps are also bucketed in this histogram using negative indices
- // (see below).
+ // #getSanitizedRootIndex}). Apps are also bucketed in this histogram.
// Do not change or rearrange these values, that will break historical data. Only add to the end
// of the list.
- private static final int ROOT_NONE = 0;
- private static final int ROOT_OTHER = 1;
- private static final int ROOT_AUDIO = 2;
- private static final int ROOT_DEVICE_STORAGE = 3;
- private static final int ROOT_DOWNLOADS = 4;
- private static final int ROOT_HOME = 5;
- private static final int ROOT_IMAGES = 6;
- private static final int ROOT_RECENTS = 7;
- private static final int ROOT_VIDEOS = 8;
- private static final int ROOT_MTP = 9;
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int ROOT_NONE = 1;
+ private static final int ROOT_OTHER = 2;
+ private static final int ROOT_AUDIO = 3;
+ private static final int ROOT_DEVICE_STORAGE = 4;
+ private static final int ROOT_DOWNLOADS = 5;
+ private static final int ROOT_HOME = 6;
+ private static final int ROOT_IMAGES = 7;
+ private static final int ROOT_RECENTS = 8;
+ private static final int ROOT_VIDEOS = 9;
+ private static final int ROOT_MTP = 10;
// Apps aren't really "roots", but they are treated as such in the roots fragment UI and so they
- // are logged analogously to roots. Use negative numbers to identify apps.
- private static final int ROOT_THIRD_PARTY_APP = -1;
+ // are logged analogously to roots.
+ private static final int ROOT_THIRD_PARTY_APP = 100;
@IntDef(flag = true, value = {
ROOT_NONE,
@@ -99,19 +99,21 @@
public @interface Root {}
// Indices for bucketing mime types.
- private static final int MIME_OTHER = -2; // anything not enumerated below
- private static final int MIME_NONE = -1; // null mime
- private static final int MIME_ANY = 0; // */*
- private static final int MIME_APPLICATION = 1; // application/*
- private static final int MIME_AUDIO = 2; // audio/*
- private static final int MIME_IMAGE = 3; // image/*
- private static final int MIME_MESSAGE = 4; // message/*
- private static final int MIME_MULTIPART = 5; // multipart/*
- private static final int MIME_TEXT = 6; // text/*
- private static final int MIME_VIDEO = 7; // video/*
+ // Do not change or rearrange these values, that will break historical data. Only add to the end
+ // of the list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int MIME_NONE = 1; // null mime
+ private static final int MIME_ANY = 2; // */*
+ private static final int MIME_APPLICATION = 3; // application/*
+ private static final int MIME_AUDIO = 4; // audio/*
+ private static final int MIME_IMAGE = 5; // image/*
+ private static final int MIME_MESSAGE = 6; // message/*
+ private static final int MIME_MULTIPART = 7; // multipart/*
+ private static final int MIME_TEXT = 8; // text/*
+ private static final int MIME_VIDEO = 9; // video/*
+ private static final int MIME_OTHER = 10; // anything not enumerated below
@IntDef(flag = true, value = {
- MIME_OTHER,
MIME_NONE,
MIME_ANY,
MIME_APPLICATION,
@@ -120,25 +122,29 @@
MIME_MESSAGE,
MIME_MULTIPART,
MIME_TEXT,
- MIME_VIDEO
+ MIME_VIDEO,
+ MIME_OTHER
})
@Retention(RetentionPolicy.SOURCE)
public @interface Mime {}
// Codes representing different kinds of file operations. These are used for bucketing
// operations in the COUNT_FILEOP_{SYSTEM|EXTERNAL} histograms.
- private static final int FILEOP_OTHER = 0; // any file operation not listed below
- private static final int FILEOP_COPY_INTRA_PROVIDER = 1; // Copy within a provider
- private static final int FILEOP_COPY_SYSTEM_PROVIDER = 2; // Copy to a system provider.
- private static final int FILEOP_COPY_EXTERNAL_PROVIDER = 3; // Copy to a 3rd-party provider.
- private static final int FILEOP_MOVE_INTRA_PROVIDER = 4; // Move within a provider.
- private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 5; // Move to a system provider.
- private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 6; // Move to a 3rd-party provider.
- private static final int FILEOP_DELETE = 7;
- private static final int FILEOP_OTHER_ERROR = -1;
- private static final int FILEOP_COPY_ERROR = -2;
- private static final int FILEOP_MOVE_ERROR = -3;
- private static final int FILEOP_DELETE_ERROR = -4;
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int FILEOP_OTHER = 1; // any file operation not listed below
+ private static final int FILEOP_COPY_INTRA_PROVIDER = 2; // Copy within a provider
+ private static final int FILEOP_COPY_SYSTEM_PROVIDER = 3; // Copy to a system provider.
+ private static final int FILEOP_COPY_EXTERNAL_PROVIDER = 4; // Copy to a 3rd-party provider.
+ private static final int FILEOP_MOVE_INTRA_PROVIDER = 5; // Move within a provider.
+ private static final int FILEOP_MOVE_SYSTEM_PROVIDER = 6; // Move to a system provider.
+ private static final int FILEOP_MOVE_EXTERNAL_PROVIDER = 7; // Move to a 3rd-party provider.
+ private static final int FILEOP_DELETE = 8;
+ private static final int FILEOP_OTHER_ERROR = 100;
+ private static final int FILEOP_DELETE_ERROR = 101;
+ private static final int FILEOP_MOVE_ERROR = 102;
+ private static final int FILEOP_COPY_ERROR = 103;
@IntDef(flag = true, value = {
FILEOP_OTHER,
@@ -157,6 +163,52 @@
@Retention(RetentionPolicy.SOURCE)
public @interface FileOp {}
+ // Codes representing different kinds of file operations. These are used for bucketing
+ // operations in the COUNT_FILEOP_CANCELED histogram.
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int OPERATION_UNKNOWN = 1;
+ private static final int OPERATION_COPY = 2;
+ private static final int OPERATION_MOVE = 3;
+ private static final int OPERATION_DELETE= 4;
+
+ @IntDef(flag = true, value = {
+ OPERATION_UNKNOWN,
+ OPERATION_COPY,
+ OPERATION_MOVE,
+ OPERATION_DELETE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MetricsOpType {}
+
+ // Codes representing different launch actions. These are used for bucketing stats in the
+ // COUNT_LAUNCH_ACTION histogram.
+ // Do not change or rearrange these values, that will break historical data. Only add to the
+ // list.
+ // Do not use negative numbers or zero; clearcut only handles positive integers.
+ private static final int ACTION_OTHER = 1;
+ private static final int ACTION_OPEN = 2;
+ private static final int ACTION_CREATE = 3;
+ private static final int ACTION_GET_CONTENT = 4;
+ private static final int ACTION_OPEN_TREE = 5;
+ private static final int ACTION_MANAGE = 6;
+ private static final int ACTION_BROWSE = 7;
+ private static final int ACTION_PICK_COPY_DESTINATION = 8;
+
+ @IntDef(flag = true, value = {
+ ACTION_OTHER,
+ ACTION_OPEN,
+ ACTION_CREATE,
+ ACTION_GET_CONTENT,
+ ACTION_OPEN_TREE,
+ ACTION_MANAGE,
+ ACTION_BROWSE,
+ ACTION_PICK_COPY_DESTINATION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MetricsAction {}
+
// Codes representing different provider types. Used for sorting file operations when logging.
private static final int PROVIDER_INTRA = 0;
private static final int PROVIDER_SYSTEM = 1;
@@ -179,7 +231,7 @@
*/
public static void logActivityLaunch(Context context, State state, Intent intent) {
// Log the launch action.
- logHistogram(context, COUNT_LAUNCH_ACTION, state.action);
+ logHistogram(context, COUNT_LAUNCH_ACTION, toMetricsAction(state.action));
// Then log auxiliary data (roots/mime types) associated with some actions.
Uri uri = intent.getData();
switch (state.action) {
@@ -300,7 +352,7 @@
* @param operationType
*/
public static void logFileOperationCancelled(Context context, @OpType int operationType) {
- logHistogram(context, COUNT_FILEOP_CANCELED, operationType);
+ logHistogram(context, COUNT_FILEOP_CANCELED, toMetricsOpType(operationType));
}
private static void logInterProviderFileOps(
@@ -483,6 +535,44 @@
}
/**
+ * Maps FileOperationService OpType values, to MetricsOpType values.
+ */
+ private static @MetricsOpType int toMetricsOpType(@OpType int operation) {
+ switch (operation) {
+ case FileOperationService.OPERATION_COPY:
+ return OPERATION_COPY;
+ case FileOperationService.OPERATION_MOVE:
+ return OPERATION_MOVE;
+ case FileOperationService.OPERATION_DELETE:
+ return OPERATION_DELETE;
+ case FileOperationService.OPERATION_UNKNOWN:
+ default:
+ return OPERATION_UNKNOWN;
+ }
+ }
+
+ private static @MetricsAction int toMetricsAction(int action) {
+ switch(action) {
+ case State.ACTION_OPEN:
+ return ACTION_OPEN;
+ case State.ACTION_CREATE:
+ return ACTION_CREATE;
+ case State.ACTION_GET_CONTENT:
+ return ACTION_GET_CONTENT;
+ case State.ACTION_OPEN_TREE:
+ return ACTION_OPEN_TREE;
+ case State.ACTION_MANAGE:
+ return ACTION_MANAGE;
+ case State.ACTION_BROWSE:
+ return ACTION_BROWSE;
+ case State.ACTION_PICK_COPY_DESTINATION:
+ return ACTION_PICK_COPY_DESTINATION;
+ default:
+ return ACTION_OTHER;
+ }
+ }
+
+ /**
* Count the given src documents and provide a tally of how many come from the same provider as
* the dst document (if a dst is provided), how many come from system providers, and how many
* come from external 3rd-party providers.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
index 85cc12b..2cef8d3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/OperationDialogFragment.java
@@ -16,9 +16,6 @@
package com.android.documentsui;
-import static com.android.documentsui.services.FileOperationService.OpType;
-import static com.android.internal.util.Preconditions.checkArgument;
-
import android.annotation.IntDef;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -32,13 +29,11 @@
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.services.FileOperationService;
-import com.android.documentsui.services.FileOperations;
-import com.android.documentsui.services.Job;
+import com.android.documentsui.services.FileOperationService.OpType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.List;
/**
* Alert dialog for operation dialogs.
@@ -114,7 +109,7 @@
final StringBuilder list = new StringBuilder("<p>");
for (DocumentInfo documentInfo : srcList) {
- list.append(String.format("• %s<br>", documentInfo.displayName));
+ list.append(String.format("• %s<br>", Html.escapeHtml(documentInfo.displayName)));
}
list.append("</p>");
builder.setMessage(Html.fromHtml(String.format(messageFormat, list.toString())));
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index 287c904..32543c8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -16,8 +16,9 @@
package com.android.documentsui;
-import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
+import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
+import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
import static com.android.internal.util.Preconditions.checkArgument;
import android.app.Activity;
@@ -40,7 +41,8 @@
public static final String TAG = "PickFragment";
private int mAction;
- private @OpType int mOperationType;
+ // Only legal values are OPERATION_COPY, OPERATION_MOVE, and unset (OPERATION_UNKNOWN).
+ private @OpType int mCopyOperationSubType = OPERATION_UNKNOWN;
private DocumentInfo mPickTarget;
private View mContainer;
private Button mPick;
@@ -97,10 +99,11 @@
/**
* @param action Which action defined in State is the picker shown for.
*/
- public void setPickTarget(int action, @OpType int operationType, DocumentInfo pickTarget) {
- checkArgument(operationType == OPERATION_COPY || operationType == OPERATION_MOVE);
+ public void setPickTarget(
+ int action, @OpType int copyOperationSubType, DocumentInfo pickTarget) {
+ checkArgument(copyOperationSubType != OPERATION_DELETE);
mAction = action;
- mOperationType = operationType;
+ mCopyOperationSubType = copyOperationSubType;
mPickTarget = pickTarget;
if (mContainer != null) {
updateView();
@@ -117,7 +120,7 @@
mCancel.setVisibility(View.GONE);
break;
case State.ACTION_PICK_COPY_DESTINATION:
- mPick.setText(mOperationType == OPERATION_MOVE
+ mPick.setText(mCopyOperationSubType == OPERATION_MOVE
? R.string.button_move : R.string.button_copy);
mCancel.setVisibility(View.VISIBLE);
break;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
similarity index 92%
rename from packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
rename to packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
index 0ee54e6..cebc9b0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsLoader.java
@@ -31,12 +31,12 @@
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
import android.text.format.DateUtils;
import android.util.Log;
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
+
import com.google.common.util.concurrent.AbstractFuture;
import libcore.io.IoUtils;
@@ -52,7 +52,7 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
+public class RecentsLoader extends AsyncTaskLoader<DirectoryResult> {
// TODO: clean up cursor ownership so background thread doesn't traverse
// previously returned cursors for filtering/sorting; this currently races
// with the UI thread.
@@ -80,7 +80,7 @@
private final State mState;
@GuardedBy("mTasks")
- private final HashMap<RootInfo, RecentTask> mTasks = new HashMap<>();
+ private final HashMap<RootInfo, RecentsTask> mTasks = new HashMap<>();
private final int mSortOrder = State.SORT_ORDER_LAST_MODIFIED;
@@ -89,69 +89,7 @@
private DirectoryResult mResult;
- // TODO: create better transfer of ownership around cursor to ensure its
- // closed in all edge cases.
-
- public class RecentTask extends AbstractFuture<Cursor> implements Runnable, Closeable {
- public final String authority;
- public final String rootId;
-
- private Cursor mWithRoot;
-
- public RecentTask(String authority, String rootId) {
- this.authority = authority;
- this.rootId = rootId;
- }
-
- @Override
- public void run() {
- if (isCancelled()) return;
-
- try {
- mQueryPermits.acquire();
- } catch (InterruptedException e) {
- return;
- }
-
- try {
- runInternal();
- } finally {
- mQueryPermits.release();
- }
- }
-
- public void runInternal() {
- ContentProviderClient client = null;
- try {
- client = DocumentsApplication.acquireUnstableProviderOrThrow(
- getContext().getContentResolver(), authority);
-
- final Uri uri = DocumentsContract.buildRecentDocumentsUri(authority, rootId);
- final Cursor cursor = client.query(
- uri, null, null, null, DirectoryLoader.getQuerySortOrder(mSortOrder));
- mWithRoot = new RootCursorWrapper(authority, rootId, cursor, MAX_DOCS_FROM_ROOT);
-
- } catch (Exception e) {
- Log.w(TAG, "Failed to load " + authority + ", " + rootId, e);
- } finally {
- ContentProviderClient.releaseQuietly(client);
- }
-
- set(mWithRoot);
-
- mFirstPassLatch.countDown();
- if (mFirstPassDone) {
- onContentChanged();
- }
- }
-
- @Override
- public void close() throws IOException {
- IoUtils.closeQuietly(mWithRoot);
- }
- }
-
- public RecentLoader(Context context, RootsCache roots, State state) {
+ public RecentsLoader(Context context, RootsCache roots, State state) {
super(context);
mRoots = roots;
mState = state;
@@ -178,14 +116,13 @@
final Collection<RootInfo> roots = mRoots.getMatchingRootsBlocking(mState);
for (RootInfo root : roots) {
- if ((root.flags & Root.FLAG_SUPPORTS_RECENTS) != 0) {
- final RecentTask task = new RecentTask(root.authority, root.rootId);
- mTasks.put(root, task);
+ if (root.supportsRecents()) {
+ mTasks.put(root, new RecentsTask(root.authority, root.rootId));
}
}
mFirstPassLatch = new CountDownLatch(mTasks.size());
- for (RecentTask task : mTasks.values()) {
+ for (RecentsTask task : mTasks.values()) {
ProviderExecutor.forAuthority(task.authority).execute(task);
}
@@ -202,7 +139,7 @@
// Collect all finished tasks
boolean allDone = true;
List<Cursor> cursors = new ArrayList<>();
- for (RecentTask task : mTasks.values()) {
+ for (RecentsTask task : mTasks.values()) {
if (task.isDone()) {
try {
final Cursor cursor = task.get();
@@ -303,7 +240,7 @@
onStopLoading();
synchronized (mTasks) {
- for (RecentTask task : mTasks.values()) {
+ for (RecentsTask task : mTasks.values()) {
IoUtils.closeQuietly(task);
}
}
@@ -311,4 +248,66 @@
IoUtils.closeQuietly(mResult);
mResult = null;
}
+
+ // TODO: create better transfer of ownership around cursor to ensure its
+ // closed in all edge cases.
+
+ public class RecentsTask extends AbstractFuture<Cursor> implements Runnable, Closeable {
+ public final String authority;
+ public final String rootId;
+
+ private Cursor mWithRoot;
+
+ public RecentsTask(String authority, String rootId) {
+ this.authority = authority;
+ this.rootId = rootId;
+ }
+
+ @Override
+ public void run() {
+ if (isCancelled()) return;
+
+ try {
+ mQueryPermits.acquire();
+ } catch (InterruptedException e) {
+ return;
+ }
+
+ try {
+ runInternal();
+ } finally {
+ mQueryPermits.release();
+ }
+ }
+
+ public void runInternal() {
+ ContentProviderClient client = null;
+ try {
+ client = DocumentsApplication.acquireUnstableProviderOrThrow(
+ getContext().getContentResolver(), authority);
+
+ final Uri uri = DocumentsContract.buildRecentDocumentsUri(authority, rootId);
+ final Cursor cursor = client.query(
+ uri, null, null, null, DirectoryLoader.getQuerySortOrder(mSortOrder));
+ mWithRoot = new RootCursorWrapper(authority, rootId, cursor, MAX_DOCS_FROM_ROOT);
+
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to load " + authority + ", " + rootId, e);
+ } finally {
+ ContentProviderClient.releaseQuietly(client);
+ }
+
+ set(mWithRoot);
+
+ mFirstPassLatch.countDown();
+ if (mFirstPassDone) {
+ onContentChanged();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ IoUtils.closeQuietly(mWithRoot);
+ }
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index fd96391..216509d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -18,6 +18,7 @@
import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.Shared.TAG;
+import static com.android.internal.util.Preconditions.checkState;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -40,6 +41,7 @@
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
@@ -85,15 +87,13 @@
// Create a new anonymous "Recents" RootInfo. It's a faker.
mRecentsRoot = new RootInfo() {{
- // Special root for recents
- authority = null;
- rootId = null;
- derivedIcon = R.drawable.ic_root_recent;
- derivedType = RootInfo.TYPE_RECENTS;
- flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD;
- title = mContext.getString(R.string.root_recent);
- availableBytes = -1;
- }};
+ // Special root for recents
+ derivedIcon = R.drawable.ic_root_recent;
+ derivedType = RootInfo.TYPE_RECENTS;
+ flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD;
+ title = mContext.getString(R.string.root_recent);
+ availableBytes = -1;
+ }};
}
private class RootsChangedObserver extends ContentObserver {
@@ -116,6 +116,16 @@
* Gather roots from all known storage providers.
*/
public void updateAsync() {
+ // Verifying an assumption about the recents root being immutable.
+ if (DEBUG) {
+ checkState(mRecentsRoot.authority == null);
+ checkState(mRecentsRoot.rootId == null);
+ checkState(mRecentsRoot.derivedIcon == R.drawable.ic_root_recent);
+ checkState(mRecentsRoot.derivedType == RootInfo.TYPE_RECENTS);
+ checkState(mRecentsRoot.flags == (Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_IS_CHILD));
+ checkState(mRecentsRoot.title == mContext.getString(R.string.root_recent));
+ checkState(mRecentsRoot.availableBytes == -1);
+ }
new UpdateTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@@ -412,9 +422,10 @@
if (!state.showAdvanced && root.isAdvanced()) continue;
// Exclude non-local devices when local only
if (state.localOnly && !root.isLocalOnly()) continue;
- // Exclude downloads roots that don't support directory creation
- // TODO: Add flag to check the root supports directory creation or not.
- if (state.directoryCopy && !root.supportsChildren()) continue;
+ // Exclude downloads roots as it doesn't support directory creation (actually
+ // we just don't show them).
+ // TODO: Add flag to check the root supports directory creation.
+ if (state.directoryCopy && !root.isDownloads()) continue;
// Only show empty roots when creating, or in browse mode.
if (root.isEmpty() && (state.action == State.ACTION_OPEN
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index f908eeb..9f83c04 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -45,7 +45,6 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
import java.util.ArrayList;
@@ -403,17 +402,7 @@
public static class RootComparator implements Comparator<RootItem> {
@Override
public int compare(RootItem lhs, RootItem rhs) {
- // Sort by root type, then title, then summary.
- int score = lhs.root.derivedType - rhs.root.derivedType;
- if (score != 0) {
- return score;
- }
- score = DocumentInfo.compareToIgnoreCaseNullable(lhs.root.title, rhs.root.title);
- if (score != 0) {
- return score;
- }
-
- return DocumentInfo.compareToIgnoreCaseNullable(lhs.root.summary, rhs.root.summary);
+ return lhs.root.compareTo(rhs.root);
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 22cb25a2..b90a119 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -17,14 +17,17 @@
package com.android.documentsui;
import android.content.Context;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
+import java.text.Collator;
import java.util.ArrayList;
import java.util.List;
/** @hide */
public final class Shared {
+
/** Intent action name to pick a copy destination. */
public static final String ACTION_PICK_COPY_DESTINATION =
"com.android.documentsui.PICK_COPY_DESTINATION";
@@ -39,6 +42,19 @@
public static final String TAG = "Documents";
public static final String EXTRA_STACK = "com.android.documentsui.STACK";
+
+ /**
+ * String prefix used to indicate the document is a directory.
+ */
+ public static final char DIR_PREFIX = '\001';
+
+ private static final Collator sCollator;
+
+ static {
+ sCollator = Collator.getInstance();
+ sCollator.setStrength(Collator.SECONDARY);
+ }
+
/**
* Generates a formatted quantity string.
*/
@@ -76,4 +92,26 @@
? (ArrayList<T>) list
: new ArrayList<T>(list);
}
+
+ /**
+ * Compare two strings against each other using system default collator in a
+ * case-insensitive mode. Clusters strings prefixed with {@link DIR_PREFIX}
+ * before other items.
+ */
+ public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
+ final boolean leftEmpty = TextUtils.isEmpty(lhs);
+ final boolean rightEmpty = TextUtils.isEmpty(rhs);
+
+ if (leftEmpty && rightEmpty) return 0;
+ if (leftEmpty) return -1;
+ if (rightEmpty) return 1;
+
+ final boolean leftDir = (lhs.charAt(0) == DIR_PREFIX);
+ final boolean rightDir = (rhs.charAt(0) == DIR_PREFIX);
+
+ if (leftDir && !rightDir) return -1;
+ if (rightDir && !leftDir) return 1;
+
+ return sCollator.compare(lhs, rhs);
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 81a0635..0948ab1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -30,6 +30,7 @@
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.services.FileOperationService;
import com.android.documentsui.services.FileOperationService.OpType;
import java.lang.annotation.Retention;
@@ -93,9 +94,10 @@
/**
* This is basically a sub-type for the copy operation. It can be either COPY or MOVE.
- * The only legal values are: OPERATION_COPY, OPERATION_MOVE.
+ * The only legal values, if set, are: OPERATION_COPY, OPERATION_MOVE. Other pick
+ * operations don't use this. In those cases OPERATION_UNKNOWN is also legal.
*/
- public @OpType int copyOperationSubType;
+ public @OpType int copyOperationSubType = FileOperationService.OPERATION_UNKNOWN;
/** Current user navigation stack; empty implies recents. */
public DocumentStack stack = new DocumentStack();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 236fa94..4583dec 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -88,7 +88,7 @@
import com.android.documentsui.MessageBar;
import com.android.documentsui.MimePredicate;
import com.android.documentsui.R;
-import com.android.documentsui.RecentLoader;
+import com.android.documentsui.RecentsLoader;
import com.android.documentsui.RootsCache;
import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
@@ -268,13 +268,13 @@
mSelectionManager.addCallback(selectionListener);
- // Make sure this is done after the RecyclerView is set up.
- mFocusManager = new FocusManager(mRecView);
-
mModel = new Model();
mModel.addUpdateListener(mAdapter);
mModel.addUpdateListener(mModelUpdateListener);
+ // Make sure this is done after the RecyclerView is set up.
+ mFocusManager = new FocusManager(context, mRecView, mModel);
+
mType = getArguments().getInt(EXTRA_TYPE);
mTuner = FragmentTuner.pick(getContext(), state);
@@ -320,7 +320,7 @@
context, mType, root, doc, contentsUri, state.userSortOrder);
case TYPE_RECENT_OPEN:
final RootsCache roots = DocumentsApplication.getRootsCache(context);
- return new RecentLoader(context, roots, state);
+ return new RecentsLoader(context, roots, state);
default:
throw new IllegalStateException("Unknown type " + mType);
}
@@ -1071,8 +1071,8 @@
return false;
}
- // Can't copy folders to roots that don't support children.
- if (!root.supportsChildren()) {
+ // Can't copy folders to downloads, because we don't show folders there.
+ if (!root.isDownloads()) {
for (DocumentInfo docs : files) {
if (docs.isDirectory()) {
return false;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
index e90a447..7f867d5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FocusManager.java
@@ -16,13 +16,28 @@
package com.android.documentsui.dirlist;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.content.Context;
+import android.provider.DocumentsContract.Document;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
+import android.text.Editable;
+import android.text.Spannable;
+import android.text.method.KeyListener;
+import android.text.method.TextKeyListener;
+import android.text.method.TextKeyListener.Capitalize;
+import android.text.style.BackgroundColorSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
+import android.widget.TextView;
import com.android.documentsui.Events;
+import com.android.documentsui.R;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* A class that handles navigation and focus within the DirectoryFragment.
@@ -31,15 +46,21 @@
private static final String TAG = "FocusManager";
private RecyclerView mView;
- private RecyclerView.Adapter<?> mAdapter;
+ private DocumentsAdapter mAdapter;
private GridLayoutManager mLayout;
+ private TitleSearchHelper mSearchHelper;
+ private Model mModel;
+
private int mLastFocusPosition = RecyclerView.NO_POSITION;
- public FocusManager(RecyclerView view) {
+ public FocusManager(Context context, RecyclerView view, Model model) {
mView = view;
- mAdapter = view.getAdapter();
+ mAdapter = (DocumentsAdapter) view.getAdapter();
mLayout = (GridLayoutManager) view.getLayoutManager();
+ mModel = model;
+
+ mSearchHelper = new TitleSearchHelper(context);
}
/**
@@ -52,7 +73,11 @@
* @return Whether the event was handled.
*/
public boolean handleKey(DocumentHolder doc, int keyCode, KeyEvent event) {
- boolean extendSelection = false;
+ // Search helper gets first crack, for doing type-to-focus.
+ if (mSearchHelper.handleKey(doc, keyCode, event)) {
+ return true;
+ }
+
// Translate space/shift-space into PgDn/PgUp
if (keyCode == KeyEvent.KEYCODE_SPACE) {
if (event.isShiftPressed()) {
@@ -60,8 +85,6 @@
} else {
keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
}
- } else {
- extendSelection = event.isShiftPressed();
}
if (Events.isNavigationKeyCode(keyCode)) {
@@ -236,7 +259,6 @@
if (vh != null) {
vh.itemView.requestFocus();
} else {
- mView.smoothScrollToPosition(pos);
// Set a one-time listener to request focus when the scroll has completed.
mView.addOnScrollListener(
new RecyclerView.OnScrollListener() {
@@ -258,6 +280,7 @@
}
}
});
+ mView.smoothScrollToPosition(pos);
}
}
@@ -267,4 +290,239 @@
private boolean inGridMode() {
return mLayout.getSpanCount() > 1;
}
+
+ /**
+ * A helper class for handling type-to-focus. Instantiate this class, and pass it KeyEvents via
+ * the {@link #handleKey(DocumentHolder, int, KeyEvent)} method. The class internally will build
+ * up a string from individual key events, and perform searching based on that string. When an
+ * item is found that matches the search term, that item will be focused. This class also
+ * highlights instances of the search term found in the view.
+ */
+ private class TitleSearchHelper {
+ final private KeyListener mTextListener = new TextKeyListener(Capitalize.NONE, false);
+ final private Editable mSearchString = Editable.Factory.getInstance().newEditable("");
+ final private Highlighter mHighlighter = new Highlighter();
+ final private BackgroundColorSpan mSpan;
+ private List<String> mIndex;
+ private boolean mActive;
+
+ public TitleSearchHelper(Context context) {
+ mSpan = new BackgroundColorSpan(context.getColor(R.color.accent_dark));
+ }
+
+ /**
+ * Handles alphanumeric keystrokes for type-to-focus. This method builds a search term out
+ * of individual key events, and then performs a search for the given string.
+ *
+ * @param doc The document holder receiving the key event.
+ * @param keyCode
+ * @param event
+ * @return Whether the event was handled.
+ */
+ public boolean handleKey(DocumentHolder doc, int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_ESCAPE:
+ case KeyEvent.KEYCODE_ENTER:
+ if (mActive) {
+ // These keys end any active searches.
+ deactivate();
+ return true;
+ } else {
+ // Don't handle these key events if there is no active search.
+ return false;
+ }
+ case KeyEvent.KEYCODE_SPACE:
+ // This allows users to search for files with spaces in their names, but ignores
+ // spacebar events when a text search is not active.
+ if (!mActive) {
+ return false;
+ }
+ }
+
+ // Navigation keys also end active searches.
+ if (Events.isNavigationKeyCode(keyCode)) {
+ deactivate();
+ // Don't handle the keycode, so navigation still occurs.
+ return false;
+ }
+
+ // Build up the search string, and perform the search.
+ boolean handled = mTextListener.onKeyDown(doc.itemView, mSearchString, keyCode, event);
+
+ // Delete is processed by the text listener, but not "handled". Check separately for it.
+ if (handled || keyCode == KeyEvent.KEYCODE_DEL) {
+ String searchString = mSearchString.toString();
+ if (searchString.length() == 0) {
+ // Don't perform empty searches.
+ return false;
+ }
+ activate();
+ for (int pos = 0; pos < mIndex.size(); pos++) {
+ String title = mIndex.get(pos);
+ if (title != null && title.startsWith(searchString)) {
+ focusItem(pos);
+ break;
+ }
+ }
+ }
+
+ return handled;
+ }
+
+ /**
+ * Activates the search helper, which changes its key handling and updates the search index
+ * and highlights if necessary. Call this each time the search term is updated.
+ */
+ private void activate() {
+ if (!mActive) {
+ // Install listeners.
+ mModel.addUpdateListener(mModelListener);
+ }
+
+ // If the search index was invalidated, rebuild it
+ if (mIndex == null) {
+ buildIndex();
+ }
+
+ // TODO: Uncomment this to enable search term highlighting in the UI.
+// mHighlighter.activate();
+
+ mActive = true;
+ }
+
+ /**
+ * Deactivates the search helper (see {@link #activate()}). Call this when a search ends.
+ */
+ private void deactivate() {
+ if (mActive) {
+ // Remove listeners.
+ mModel.removeUpdateListener(mModelListener);
+ }
+
+ // TODO: Uncomment this when search-term highlighting is enabled in the UI.
+// mHighlighter.deactivate();
+
+ mIndex = null;
+ mSearchString.clear();
+ mActive = false;
+ }
+
+ /**
+ * Applies title highlights to the given view. The view must have a title field that is a
+ * spannable text field. If this condition is not met, this function does nothing.
+ *
+ * @param view
+ */
+ private void applyHighlight(View view) {
+ TextView titleView = (TextView) view.findViewById(android.R.id.title);
+ if (titleView == null) {
+ return;
+ }
+
+ String searchString = mSearchString.toString();
+ CharSequence tmpText = titleView.getText();
+ if (tmpText instanceof Spannable) {
+ Spannable title = (Spannable) tmpText;
+ String titleString = title.toString();
+ if (titleString.startsWith(searchString)) {
+ title.setSpan(mSpan, 0, searchString.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ } else {
+ title.removeSpan(mSpan);
+ }
+ }
+ }
+
+ /**
+ * Removes title highlights from the given view. The view must have a title field that is a
+ * spannable text field. If this condition is not met, this function does nothing.
+ *
+ * @param view
+ */
+ private void removeHighlight(View view) {
+ TextView titleView = (TextView) view.findViewById(android.R.id.title);
+ if (titleView == null) {
+ return;
+ }
+
+ CharSequence tmpText = titleView.getText();
+ if (tmpText instanceof Spannable) {
+ ((Spannable) tmpText).removeSpan(mSpan);
+ }
+ }
+
+ /**
+ * Builds a search index for finding items by title. Queries the model and adapter, so both
+ * must be set up before calling this method.
+ */
+ private void buildIndex() {
+ int itemCount = mAdapter.getItemCount();
+ List<String> index = new ArrayList<>(itemCount);
+ for (int i = 0; i < itemCount; i++) {
+ String modelId = mAdapter.getModelId(i);
+ if (modelId != null) {
+ index.add(
+ getCursorString(mModel.getItem(modelId), Document.COLUMN_DISPLAY_NAME));
+ } else {
+ index.add("");
+ }
+ }
+ mIndex = index;
+ }
+
+ private Model.UpdateListener mModelListener = new Model.UpdateListener() {
+ @Override
+ public void onModelUpdate(Model model) {
+ // Invalidate the search index when the model updates.
+ mIndex = null;
+ }
+
+ @Override
+ public void onModelUpdateFailed(Exception e) {
+ // Invalidate the search index when the model updates.
+ mIndex = null;
+ }
+ };
+
+ private class Highlighter implements RecyclerView.OnChildAttachStateChangeListener {
+ /**
+ * Starts highlighting instances of the current search term in the UI.
+ */
+ public void activate() {
+ // Update highlights on all views
+ int itemCount = mView.getChildCount();
+ for (int i = 0; i < itemCount; i++) {
+ applyHighlight(mView.getChildAt(i));
+ }
+ // Keep highlights up-to-date as items come in and out of view.
+ mView.addOnChildAttachStateChangeListener(this);
+ }
+
+ /**
+ * Stops highlighting instances of the current search term in the UI.
+ */
+ public void deactivate() {
+ // Remove highlights on all views
+ int itemCount = mView.getChildCount();
+ for (int i = 0; i < itemCount; i++) {
+ removeHighlight(mView.getChildAt(i));
+ }
+ // Stop updating highlights.
+ mView.removeOnChildAttachStateChangeListener(this);
+ }
+
+ @Override
+ public void onChildViewAttachedToWindow(View view) {
+ applyHighlight(view);
+ }
+
+ @Override
+ public void onChildViewDetachedFromWindow(View view) {
+ TextView titleView = (TextView) view.findViewById(android.R.id.title);
+ if (titleView != null) {
+ removeHighlight(titleView);
+ }
+ }
+ };
+ }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
index 055adc6a..8eaed17e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -32,7 +32,6 @@
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.documentsui.IconUtils;
import com.android.documentsui.R;
import com.android.documentsui.RootCursorWrapper;
import com.android.documentsui.Shared;
@@ -107,7 +106,7 @@
if (mHideTitles) {
mTitle.setVisibility(View.GONE);
} else {
- mTitle.setText(docDisplayName);
+ mTitle.setText(docDisplayName, TextView.BufferType.SPANNABLE);
mTitle.setVisibility(View.VISIBLE);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
index 8c3b53c..be6413b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -103,7 +103,7 @@
final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMime, null);
- mTitle.setText(docDisplayName);
+ mTitle.setText(docDisplayName, TextView.BufferType.SPANNABLE);
mTitle.setVisibility(View.VISIBLE);
if (docSummary != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index 3a45995..9684a5a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -35,6 +35,7 @@
import com.android.documentsui.DirectoryResult;
import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
@@ -170,7 +171,7 @@
final String displayName = getCursorString(
mCursor, Document.COLUMN_DISPLAY_NAME);
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
- stringValues[pos] = DocumentInfo.DIR_PREFIX + displayName;
+ stringValues[pos] = Shared.DIR_PREFIX + displayName;
} else {
stringValues[pos] = displayName;
}
@@ -227,7 +228,7 @@
final String lhs = pivotValue;
final String rhs = sortKey[mid];
- final int compare = DocumentInfo.compareToIgnoreCaseNullable(lhs, rhs);
+ final int compare = Shared.compareToIgnoreCaseNullable(lhs, rhs);
if (compare < 0) {
right = mid;
@@ -391,6 +392,10 @@
mUpdateListeners.add(listener);
}
+ void removeUpdateListener(UpdateListener listener) {
+ mUpdateListeners.remove(listener);
+ }
+
static interface UpdateListener {
/**
* Called when a successful update has occurred.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index 69a6711..dd27790 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -182,7 +182,7 @@
@Override
public void unhide(SparseArray<String> ids) {
- if (DEBUG) Log.d(TAG, "Un-iding ids: " + ids);
+ if (DEBUG) Log.d(TAG, "Unhiding ids: " + ids);
// An ArrayList can shrink at runtime...and in fact
// it does when we clear it completely.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 1c696ad..e9fdab0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -26,7 +26,6 @@
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsProvider;
import android.support.annotation.VisibleForTesting;
-import android.text.TextUtils;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.RootCursorWrapper;
@@ -38,7 +37,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ProtocolException;
-import java.text.Collator;
import java.util.Objects;
/**
@@ -48,13 +46,6 @@
private static final int VERSION_INIT = 1;
private static final int VERSION_SPLIT_URI = 2;
- private static final Collator sCollator;
-
- static {
- sCollator = Collator.getInstance();
- sCollator.setStrength(Collator.SECONDARY);
- }
-
public String authority;
public String documentId;
public String mimeType;
@@ -320,31 +311,4 @@
fnfe.initCause(t);
throw fnfe;
}
-
- /**
- * String prefix used to indicate the document is a directory.
- */
- public static final char DIR_PREFIX = '\001';
-
- /**
- * Compare two strings against each other using system default collator in a
- * case-insensitive mode. Clusters strings prefixed with {@link #DIR_PREFIX}
- * before other items.
- */
- public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
- final boolean leftEmpty = TextUtils.isEmpty(lhs);
- final boolean rightEmpty = TextUtils.isEmpty(rhs);
-
- if (leftEmpty && rightEmpty) return 0;
- if (leftEmpty) return -1;
- if (rightEmpty) return 1;
-
- final boolean leftDir = (lhs.charAt(0) == DIR_PREFIX);
- final boolean rightDir = (rhs.charAt(0) == DIR_PREFIX);
-
- if (leftDir && !rightDir) return -1;
- if (rightDir && !leftDir) return 1;
-
- return sCollator.compare(lhs, rhs);
- }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 8cbbb6c..3897058 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -16,10 +16,12 @@
package com.android.documentsui.model;
+import static com.android.documentsui.Shared.compareToIgnoreCaseNullable;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import android.annotation.IntDef;
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
@@ -36,17 +38,31 @@
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.ProtocolException;
import java.util.Objects;
/**
* Representation of a {@link Root}.
*/
-public class RootInfo implements Durable, Parcelable {
+public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
private static final int VERSION_INIT = 1;
private static final int VERSION_DROP_TYPE = 2;
// The values of these constants determine the sort order of various roots in the RootsFragment.
+ @IntDef(flag = true, value = {
+ TYPE_IMAGES,
+ TYPE_VIDEO,
+ TYPE_AUDIO,
+ TYPE_RECENTS,
+ TYPE_DOWNLOADS,
+ TYPE_LOCAL,
+ TYPE_MTP,
+ TYPE_OTHER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RootType {}
public static final int TYPE_IMAGES = 1;
public static final int TYPE_VIDEO = 2;
public static final int TYPE_AUDIO = 3;
@@ -69,7 +85,7 @@
/** Derived fields that aren't persisted */
public String[] derivedMimeTypes;
public int derivedIcon;
- public int derivedType;
+ public @RootType int derivedType;
public RootInfo() {
reset();
@@ -241,8 +257,10 @@
}
public boolean isLibrary() {
- return derivedType == TYPE_IMAGES || derivedType == TYPE_VIDEO || derivedType == TYPE_AUDIO
- || derivedType == TYPE_RECENTS || derivedType == TYPE_DOWNLOADS;
+ return derivedType == TYPE_IMAGES
+ || derivedType == TYPE_VIDEO
+ || derivedType == TYPE_AUDIO
+ || derivedType == TYPE_RECENTS;
}
public boolean hasSettings() {
@@ -257,6 +275,14 @@
return (flags & Root.FLAG_SUPPORTS_CREATE) != 0;
}
+ public boolean supportsRecents() {
+ return (flags & Root.FLAG_SUPPORTS_RECENTS) != 0;
+ }
+
+ public boolean supportsSearch() {
+ return (flags & Root.FLAG_SUPPORTS_SEARCH) != 0;
+ }
+
public boolean isAdvanced() {
return (flags & Root.FLAG_ADVANCED) != 0;
}
@@ -319,6 +345,22 @@
}
@Override
+ public int compareTo(RootInfo other) {
+ // Sort by root type, then title, then summary.
+ int score = derivedType - other.derivedType;
+ if (score != 0) {
+ return score;
+ }
+
+ score = compareToIgnoreCaseNullable(title, other.title);
+ if (score != 0) {
+ return score;
+ }
+
+ return compareToIgnoreCaseNullable(summary, other.summary);
+ }
+
+ @Override
public String toString() {
return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
}
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 83299f0..4b0bc41 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -28,6 +28,7 @@
import com.android.documentsui.DirectoryResult;
import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
import com.android.documentsui.State;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
@@ -190,7 +191,7 @@
assertEquals(ITEM_COUNT, seen.cardinality());
for (int i = 0; i < names.size()-1; ++i) {
- assertTrue(DocumentInfo.compareToIgnoreCaseNullable(names.get(i), names.get(i+1)) <= 0);
+ assertTrue(Shared.compareToIgnoreCaseNullable(names.get(i), names.get(i+1)) <= 0);
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 441b9a7..ca5c799 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -581,6 +581,23 @@
}
}
+ void updateObject(String documentId, int deviceId, String parentId, MtpObjectInfo info) {
+ final ContentValues values = new ContentValues();
+ getObjectDocumentValues(values, deviceId, parentId, info);
+
+ mDatabase.beginTransaction();
+ try {
+ mDatabase.update(
+ TABLE_DOCUMENTS,
+ values,
+ Document.COLUMN_DOCUMENT_ID + " = ?",
+ strings(documentId));
+ mDatabase.setTransactionSuccessful();
+ } finally {
+ mDatabase.endTransaction();
+ }
+ }
+
private static class OpenHelper extends SQLiteOpenHelper {
public OpenHelper(Context context, int flags) {
super(context,
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index db1671d..d329e3c 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -486,7 +486,7 @@
public final DocumentLoader mDocumentLoader;
public DeviceToolkit(MtpManager manager, ContentResolver resolver, MtpDatabase database) {
- mPipeManager = new PipeManager();
+ mPipeManager = new PipeManager(database);
mDocumentLoader = new DocumentLoader(manager, resolver, database);
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index 16523bc..645bfcd 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -29,12 +29,14 @@
class PipeManager {
final ExecutorService mExecutor;
+ final MtpDatabase mDatabase;
- PipeManager() {
- this(Executors.newSingleThreadExecutor());
+ PipeManager(MtpDatabase database) {
+ this(database, Executors.newSingleThreadExecutor());
}
- PipeManager(ExecutorService executor) {
+ PipeManager(MtpDatabase database, ExecutorService executor) {
+ this.mDatabase = database;
this.mExecutor = executor;
}
@@ -46,7 +48,7 @@
ParcelFileDescriptor writeDocument(Context context, MtpManager model, Identifier identifier)
throws IOException {
- final Task task = new WriteDocumentTask(context, model, identifier);
+ final Task task = new WriteDocumentTask(context, model, identifier, mDatabase);
mExecutor.execute(task);
return task.getWritingFileDescriptor();
}
@@ -100,11 +102,14 @@
private static class WriteDocumentTask extends Task {
private final Context mContext;
+ private final MtpDatabase mDatabase;
- WriteDocumentTask(Context context, MtpManager model, Identifier identifier)
+ WriteDocumentTask(
+ Context context, MtpManager model, Identifier identifier, MtpDatabase database)
throws IOException {
super(model, identifier);
mContext = context;
+ mDatabase = database;
}
@Override
@@ -112,7 +117,7 @@
File tempFile = null;
try {
// Obtain a temporary file and copy the data to it.
- tempFile = mContext.getCacheDir().createTempFile("mtp", "tmp");
+ tempFile = File.createTempFile("mtp", "tmp", mContext.getCacheDir());
try (
final FileOutputStream tempOutputStream =
new ParcelFileDescriptor.AutoCloseOutputStream(
@@ -140,12 +145,22 @@
// Create the target object info with a correct file size and upload the file.
final MtpObjectInfo targetObjectInfo =
new MtpObjectInfo.Builder(placeholderObjectInfo)
- .setCompressedSize((int) tempFile.length())
+ .setCompressedSize(tempFile.length())
.build();
final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open(
tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
- mManager.createDocument(mIdentifier.mDeviceId,
- targetObjectInfo, tempInputDescriptor);
+ final int newObjectHandle = mManager.createDocument(
+ mIdentifier.mDeviceId, targetObjectInfo, tempInputDescriptor);
+
+ final MtpObjectInfo newObjectInfo = mManager.getObjectInfo(
+ mIdentifier.mDeviceId, newObjectHandle);
+ final Identifier parentIdentifier =
+ mDatabase.getParentIdentifier(mIdentifier.mDocumentId);
+ mDatabase.updateObject(
+ mIdentifier.mDocumentId,
+ mIdentifier.mDeviceId,
+ parentIdentifier.mDocumentId,
+ newObjectInfo);
} catch (IOException error) {
Log.w(MtpDocumentsProvider.TAG,
"Failed to send a file because of: " + error.getMessage());
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 1df7351..05c9c57 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -983,18 +983,10 @@
}
private void addTestDevice() throws FileNotFoundException {
- mDatabase.getMapper().startAddingDocuments(null);
- mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
- 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null,
- null));
- mDatabase.getMapper().stopAddingDocuments(null);
+ TestUtil.addTestDevice(mDatabase);
}
private void addTestStorage(String parentId) throws FileNotFoundException {
- mDatabase.getMapper().startAddingDocuments(parentId);
- mDatabase.getMapper().putStorageDocuments(parentId, new MtpRoot[] {
- new MtpRoot(0, 100, "Storage", 1024, 1024, ""),
- });
- mDatabase.getMapper().stopAddingDocuments(parentId);
+ TestUtil.addTestStorage(mDatabase, parentId);
}
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
index 4dfc785..94f87ff 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -16,8 +16,10 @@
package com.android.mtp;
+import android.database.Cursor;
import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
@@ -33,12 +35,14 @@
private TestMtpManager mtpManager;
private ExecutorService mExecutor;
private PipeManager mPipeManager;
+ private MtpDatabase mDatabase;
@Override
public void setUp() {
mtpManager = new TestMtpManager(getContext());
mExecutor = Executors.newSingleThreadExecutor();
- mPipeManager = new PipeManager(mExecutor);
+ mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ mPipeManager = new PipeManager(mDatabase, mExecutor);
}
public void testReadDocument_basic() throws Exception {
@@ -57,25 +61,32 @@
}
public void testWriteDocument_basic() throws Exception {
+ TestUtil.addTestDevice(mDatabase);
+ TestUtil.addTestStorage(mDatabase, "1");
+
+ final MtpObjectInfo info =
+ new MtpObjectInfo.Builder().setObjectHandle(1).setName("note.txt").build();
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] { info });
+ mDatabase.getMapper().stopAddingDocuments("2");
// Create a placeholder file which should be replaced by a real file later.
- mtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
- .setObjectHandle(1)
- .build());
+ mtpManager.setObjectInfo(0, info);
// Upload testing bytes.
final ParcelFileDescriptor descriptor = mPipeManager.writeDocument(
getContext(),
mtpManager,
- new Identifier(0, 0, 1, null, MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT));
+ new Identifier(0, 0, 1, "2", MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT));
final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
new ParcelFileDescriptor.AutoCloseOutputStream(descriptor);
outputStream.write(HELLO_BYTES, 0, HELLO_BYTES.length);
outputStream.close();
- mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+ mExecutor.shutdown();
+ assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
// Check if the placeholder file is removed.
try {
- final MtpObjectInfo placeholderDocument = mtpManager.getObjectInfo(0, 1);
+ mtpManager.getObjectInfo(0, 1);
fail(); // The placeholder file has not been deleted.
} catch (IOException e) {
// Expected error, as the file is gone.
@@ -86,6 +97,14 @@
0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
assertTrue(targetDocument != null);
+ // Confirm the object handle is updated.
+ try (final Cursor cursor = mDatabase.queryDocument(
+ "2", new String[] { MtpDatabaseConstants.COLUMN_OBJECT_HANDLE })) {
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals(TestMtpManager.CREATED_DOCUMENT_HANDLE, cursor.getInt(0));
+ }
+
// Verify uploaded bytes.
final byte[] uploadedBytes = mtpManager.getImportFileBytes(
0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
@@ -112,7 +131,8 @@
private void assertDescriptor(ParcelFileDescriptor descriptor, byte[] expectedBytes)
throws IOException, InterruptedException {
- mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+ mExecutor.shutdown();
+ assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
try (final ParcelFileDescriptor.AutoCloseInputStream stream =
new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
byte[] results = new byte[100];
@@ -125,7 +145,8 @@
private void assertDescriptorError(ParcelFileDescriptor descriptor)
throws InterruptedException {
- mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+ mExecutor.shutdown();
+ assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS));
try {
descriptor.checkError();
fail();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 4378152..1b46f3c 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -149,7 +149,9 @@
if (mObjectInfos.containsKey(key)) {
throw new IOException();
}
- mObjectInfos.put(key, objectInfo);
+ final MtpObjectInfo newInfo = new MtpObjectInfo.Builder(objectInfo).
+ setObjectHandle(CREATED_DOCUMENT_HANDLE).build();
+ mObjectInfos.put(key, newInfo);
if (objectInfo.getFormat() != 0x3001) {
try (final ParcelFileDescriptor.AutoCloseInputStream inputStream =
new ParcelFileDescriptor.AutoCloseInputStream(source)) {
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
index ffcc088..34dd77b 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
@@ -21,12 +21,11 @@
import android.hardware.usb.UsbManager;
import android.os.SystemClock;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Objects;
-import junit.framework.Assert;
-
/**
* Static utility methods for testing.
*/
@@ -57,6 +56,22 @@
}
}
+ static void addTestDevice(MtpDatabase database) throws FileNotFoundException {
+ database.getMapper().startAddingDocuments(null);
+ database.getMapper().putDeviceDocument(new MtpDeviceRecord(
+ 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null,
+ null));
+ database.getMapper().stopAddingDocuments(null);
+ }
+
+ static void addTestStorage(MtpDatabase database, String parentId) throws FileNotFoundException {
+ database.getMapper().startAddingDocuments(parentId);
+ database.getMapper().putStorageDocuments(parentId, new MtpRoot[] {
+ new MtpRoot(0, 100, "Storage", 1024, 1024, ""),
+ });
+ database.getMapper().stopAddingDocuments(parentId);
+ }
+
private static UsbDevice findMtpDevice(
UsbManager usbManager,
MtpManager manager) throws IOException {
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 2ddb1e9..99699b9 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Programme verplig ekstern toegelaat"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Laat enige program na ekstern geskryf word, ongeag manifeswaardes"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Verplig verstelbare groottes vir aktiwiteite"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Maak grootte van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Maak die groottes van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktiveer vormvrye-Windows"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiveer steun vir eksperimentele vormvrye-Windows."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktiveer steun vir eksperimentele vormvrye-Windows."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Werkskerm-rugsteunwagwoord"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volle rekenaarrugsteune word nie tans beskerm nie"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tik om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Gedeaktiveer"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Altyd aan"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Outomaties"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stel WebView-implementering"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Die gekose WebView-toepassing is gedeaktiveer, maar moet geaktiveer wees om gebruik te word. Wil jy dit aktiveer?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kleurregstelling"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Hierdie kenmerk is eksperimenteel en kan werkverrigting beïnvloed."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ongeveer <xliff:g id="TIME">%1$s</xliff:g> oor"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – sowat <xliff:g id="TIME">%2$s</xliff:g> oor"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> tot vol"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Vol"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Gedeaktiveer deur administrateur"</string>
<string name="home" msgid="8263346537524314127">"Tuis"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> gelede"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> oor"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4276bea..0e363b5 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"በውጫዊ ላይ ሃይል ይፈቀዳል"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"አንጸባራቂ እሴቶች ግምት ውስጥ ሳይገቡ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻ ለመጻፍ ብቁ ያደርጋል።"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"እንቅስቃሴዎች ዳግመኛ እንዲመጣጠኑ አስገድድ"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች ዳግም የሚመጣጠኑ እንዲሆኑ ያደርጋቸዋል።"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች መጠናቸው የሚቀየሩ እንዲሆኑ ያደርጋቸዋል።"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"የሙከራ ነጻ ቅርጽ መስኮቶች ድጋፍን ያነቃል።"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"የሙከራ ነጻ መልክ መስኮቶች ድጋፍን አንቃ"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"የዴስክቶፕ መጠባበቂያ ይለፍ ቃል"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ዴስክቶፕ ሙሉ ምትኬዎች በአሁኑ ሰዓት አልተጠበቁም"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"የዴስክቶፕ ሙሉ ምትኬዎች የይለፍ ቃሉን ለመለወጥ ወይም ለማስወገድ ነካ ያድርጉ"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"ተሰናክሏል"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ሁልጊዜ ይበራል"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ራስ-ሰር"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"የWebView ትግበራ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"የWebView ትግበራን ያዘጋጁ"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"የተመረጠው WebView ትግበራ ተሰናክሏል፣ እና ጥቅም ላይ እንዲውል መንቃት አለበት፣ ሊያነቁት ይፈልጋሉ?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"የቀለም ማስተካከያ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ይህ ባህሪ የሙከራ ነውና አፈጻጸም ላይ ተጽዕኖ ሊኖረው ይችላል።"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"በ<xliff:g id="TITLE">%1$s</xliff:g> ተሽሯል"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"<xliff:g id="TIME">%1$s</xliff:g> ገደማ ቀርቷል"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ገደማ <xliff:g id="TIME">%2$s</xliff:g> ይቀራል"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> እስከሚሞላ ድረስ"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"ሙሉነው"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"በአስተዳዳሪ የተሰናከለ"</string>
<string name="home" msgid="8263346537524314127">"መነሻ"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"ከ<xliff:g id="ID_1">%1$s</xliff:g> በፊት"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ቀርቷል"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 67fb59c..c757b71 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"فرض السماح للتطبيقات على الخارجي"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"تأهيل أي تطبيق بحيث تتم كتابته على سعة تخزين خارجية، بغض النظر عن قيم البيان"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"فرض إمكانية تغيير على الأنشطة"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"لتمكين تغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"تمكين تغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"تمكين النوافذ الحرة"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"لتمكين إتاحة استخدام النوافذ الحرة التجريبية."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"تمكين إتاحة استخدام النوافذ الحرة التجريبية."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"كلمة مرور احتياطية للكمبيوتر"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"النسخ الاحتياطية الكاملة لسطح المكتب غير محمية في الوقت الحالي"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"انقر لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها."</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"معطَّل"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"التشغيل دائمًا"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"تلقائيًا"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"تطبيق WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تعيين تطبيق WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"إن تنفيذ ميزة WebView التي تم اختيارها معطَّل، ويجب تمكين هذه الميزة ليتسنى استخدامها، فهل تريد تمكينها؟"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"تصحيح الألوان"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"هذه الميزة تجريبية وقد تؤثر في الأداء."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"يتبقى <xliff:g id="TIME">%1$s</xliff:g> تقريبًا"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - تبقى <xliff:g id="TIME">%2$s</xliff:g> تقريبًا"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> حتى الاكتمال"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"ممتلئة"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"تم التعطيل بواسطة المشرف"</string>
<string name="home" msgid="8263346537524314127">"الشاشة الرئيسية"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"قبل <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"يتبقى <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 12b077e..61008b9 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Tətbiqlərə xaricdən məcburi icazə"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Seçilmiş hər hansı tətbiqi bəyannamə dəyərlərindən aslı olmayaraq xarici yaddaşa yazılabilən edir."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Ölçü dəyişdirmək üçün məcburi fəaliyyətlər"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Bəyannamə dəyərlərindən aslı olmayaraq bütün fəaliyyətləri çoxsaylı pəncərə üçün dəyişkən ölçülü edir."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Bəyannamə dəyərlərindən aslı olmayaraq, bütün fəaliyyətləri çoxsaylı pəncərə üçün dəyişkən ölçülü edin."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Freeform windows aktiv edin"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Sınaq üçün freeform windows aktiv edir"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Sınaq üçün freeform windows aktiv edilir."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü rezerv parolu"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam rezervlər hazırda qorunmayıblar."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Masaüstünün tam rezerv kopyalanması üçün parolu dəyişmək və ya silmək üçün basın"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Qeyri-aktiv"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Həmişə aktiv"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView icrası"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView icrasını ayarlayın"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Seçilmiş WebView icrası deaktiv edildi, istifadəsi üçün aktiv edilməlidir, aktivləşdirmək istəyirsiniz?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Rəng düzəlişi"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu funksiya eksperimentaldır və performansa təsir edə bilər."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Təxminən <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Təxminən <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - təxminən <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> dolana qədər"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index ae56978..7021ca6 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Prinudno dozvoli aplikacije u spoljnoj"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Prinudno omogući promenu veličine aktivnosti"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Omogućava promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogući promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore proizvoljnog formata"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogućava podršku za eksperimentalne prozore proizvoljnog formata."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogućite podršku za eksperimentalne prozore proizvoljnog formata."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka rezervne kopije za računar"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Uvek uključeno"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatski"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Primena WebView-a"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesite primenu WebView-a"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Izabrana primena WebView-a je onemogućena, a mora da bude omogućena radi korišćenja. Želite li da je omogućite?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcija boja"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova funkcija je eksperimentalna i može da utiče na performanse."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još otprilike <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo oko <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> dok se ne napuni"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio je administrator"</string>
<string name="home" msgid="8263346537524314127">"Početni"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Pre <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index ad0ace4..df47ad9 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Външно хран.: Принуд. разрешаване на приложенията"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Позволява прилож. да се записват във външ. хранил. независимо от стойностите в манифеста"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Възможност за преоразмеряване на активностите"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Активиране на прозорците в свободна форма"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Активира поддръжката за експерименталните прозорци в свободна форма."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Активиране на поддръжката за експерименталните прозорци в свободна форма."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Наст. комп.: Парола"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Деактивирано"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Винаги включено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Внедряване на WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Задаване на внедряването на WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Избраното внедряване на WebView е деактивирано и трябва да го активирате, за да се използва. Искате ли да го направите?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Корекция на цветове"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Тази функция е експериментална и може да се отрази на ефективността."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Прибл. оставащо време: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – приблизително оставащо време: <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Пълна"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Деактивирано от администратора"</string>
<string name="home" msgid="8263346537524314127">"Начало"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Преди <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Оставащо време: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index 589c52e..e982a36 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"বহিরাগততে বলপূর্বক মঞ্জুরি"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলিকে আকার পরিবর্তনযোগ্য করে তোলে৷"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলিকে আকার পরিবর্তনযোগ্য করুন৷"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ফ্রি-ফর্ম উইন্ডোগুলি সক্ষম করুন"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ডেস্কটপের সম্পূর্ণ ব্যাকআপের পাসওয়ার্ডটি পরিবর্তন করতে বা মুছে ফেলতে আলতো চাপুন"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"অক্ষম করা রয়েছে"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"সবসময় চালু"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"স্বয়ংক্রিয়"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"ওয়েবভিউ প্রয়োগ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ওয়েবভিউ প্রয়োগ সেট করুন"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"নির্বাচিত ওয়েবভিউ প্রয়োগটি অক্ষম করা আছে এবং ব্যবহার করার জন্য অবশ্যই সক্ষম করতে হবে, আপনি কি এটিকে সক্ষম করতে চান?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"রঙ সংশোধন"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"এই বৈশিষ্ট্যটি পরীক্ষামূলক এবং এটি কার্য-সম্পাদনা প্রভাবিত করতে পারে।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> এর দ্বারা ওভাররাইড করা হয়েছে"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"প্রায় <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"প্রায় <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - আনুমানিক <xliff:g id="TIME">%2$s</xliff:g> বাকি আছে"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - সম্পূর্ণ হতে <xliff:g id="TIME">%2$s</xliff:g> বাকি"</string>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index 8da12cb..92c7ec8 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -20,130 +20,69 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for wifi_fail_to_scan (1265540342578081461) -->
- <skip />
- <!-- no translation found for wifi_security_none (7985461072596594400) -->
- <skip />
- <!-- no translation found for wifi_remembered (4955746899347821096) -->
- <skip />
- <!-- no translation found for wifi_disabled_generic (4259794910584943386) -->
- <skip />
- <!-- no translation found for wifi_disabled_network_failure (2364951338436007124) -->
- <skip />
- <!-- no translation found for wifi_disabled_wifi_failure (3081668066612876581) -->
- <skip />
- <!-- no translation found for wifi_disabled_password_failure (8659805351763133575) -->
- <skip />
- <!-- no translation found for wifi_not_in_range (1136191511238508967) -->
- <skip />
- <!-- no translation found for wifi_no_internet (9151470775868728896) -->
- <skip />
- <!-- no translation found for saved_network (4352716707126620811) -->
- <skip />
- <!-- no translation found for connected_via_wfa (3805736726317410714) -->
- <skip />
- <!-- no translation found for connected_via_passpoint (2826205693803088747) -->
- <skip />
- <!-- no translation found for available_via_passpoint (1617440946846329613) -->
- <skip />
- <!-- no translation found for wifi_connected_no_internet (3149853966840874992) -->
- <skip />
- <!-- no translation found for bluetooth_disconnected (6557104142667339895) -->
- <skip />
- <!-- no translation found for bluetooth_disconnecting (8913264760027764974) -->
- <skip />
- <!-- no translation found for bluetooth_connecting (8555009514614320497) -->
- <skip />
- <!-- no translation found for bluetooth_connected (6038755206916626419) -->
- <skip />
- <!-- no translation found for bluetooth_pairing (1426882272690346242) -->
- <skip />
- <!-- no translation found for bluetooth_connected_no_headset (2866994875046035609) -->
- <skip />
- <!-- no translation found for bluetooth_connected_no_a2dp (4576188601581440337) -->
- <skip />
- <!-- no translation found for bluetooth_connected_no_map (6504436917057479986) -->
- <skip />
- <!-- no translation found for bluetooth_connected_no_headset_no_a2dp (9195757766755553810) -->
- <skip />
- <!-- no translation found for bluetooth_profile_a2dp (2031475486179830674) -->
- <skip />
- <!-- no translation found for bluetooth_profile_headset (8658779596261212609) -->
- <skip />
- <!-- no translation found for bluetooth_profile_opp (9168139293654233697) -->
- <skip />
- <!-- no translation found for bluetooth_profile_hid (3680729023366986480) -->
- <skip />
- <!-- no translation found for bluetooth_profile_pan (3391606497945147673) -->
- <skip />
- <!-- no translation found for bluetooth_profile_pbap (5372051906968576809) -->
- <skip />
- <!-- no translation found for bluetooth_profile_pbap_summary (6605229608108852198) -->
- <skip />
- <!-- no translation found for bluetooth_profile_pan_nap (8429049285027482959) -->
- <skip />
- <!-- no translation found for bluetooth_profile_map (5465271250454324383) -->
- <skip />
- <!-- no translation found for bluetooth_profile_sap (5764222021851283125) -->
- <skip />
- <!-- no translation found for bluetooth_a2dp_profile_summary_connected (963376081347721598) -->
- <skip />
- <!-- no translation found for bluetooth_headset_profile_summary_connected (7661070206715520671) -->
- <skip />
- <!-- no translation found for bluetooth_opp_profile_summary_connected (2611913495968309066) -->
- <skip />
- <!-- no translation found for bluetooth_map_profile_summary_connected (8191407438851351713) -->
- <skip />
- <!-- no translation found for bluetooth_sap_profile_summary_connected (8561765057453083838) -->
- <skip />
- <!-- no translation found for bluetooth_opp_profile_summary_not_connected (1267091356089086285) -->
- <skip />
- <!-- no translation found for bluetooth_hid_profile_summary_connected (3381760054215168689) -->
- <skip />
+ <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ne može skenirati mreže"</string>
+ <string name="wifi_security_none" msgid="7985461072596594400">"Nema"</string>
+ <string name="wifi_remembered" msgid="4955746899347821096">"Sačuvano"</string>
+ <string name="wifi_disabled_generic" msgid="4259794910584943386">"Onemogućeno"</string>
+ <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Greška u konfiguraciji IP-a"</string>
+ <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Greška pri povezivanju na Wi-Fi"</string>
+ <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem pri provjeri vjerodostojnosti."</string>
+ <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u dometu"</string>
+ <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije pronađen. Neće se ponovo povezivati automatski."</string>
+ <string name="saved_network" msgid="4352716707126620811">"Sačuvao <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_via_wfa" msgid="3805736726317410714">"Povezani preko Wi-Fi pomoćnika"</string>
+ <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezani preko %1$s"</string>
+ <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupan preko %1$s"</string>
+ <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Povezano. Nema interneta"</string>
+ <string name="bluetooth_disconnected" msgid="6557104142667339895">"Isključen"</string>
+ <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Prekidanje veze…"</string>
+ <string name="bluetooth_connecting" msgid="8555009514614320497">"Povezivanje…"</string>
+ <string name="bluetooth_connected" msgid="6038755206916626419">"Povezano"</string>
+ <string name="bluetooth_pairing" msgid="1426882272690346242">"Uparivanje…"</string>
+ <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Povezano (bez telefona)"</string>
+ <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Povezano (bez medija)"</string>
+ <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Povezano (bez pristupa porukama)"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Povezano (bez zvuka telefona ili medija)"</string>
+ <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvuk medija"</string>
+ <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Zvuk telefona"</string>
+ <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prenošenje fajla"</string>
+ <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Ulazni uređaj"</string>
+ <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Pristup internetu"</string>
+ <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Dijeljenje kontakta"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Koristi za dijeljenje kontakta"</string>
+ <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Dijeljenje internet veze"</string>
+ <string name="bluetooth_profile_map" msgid="5465271250454324383">"Pristup poruci"</string>
+ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Pristup SIM-u"</string>
+ <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezano sa zvukom medija"</string>
+ <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezano na zvuk telefona"</string>
+ <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezan na server za prijenos podataka"</string>
+ <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Povezano na mapu"</string>
+ <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Povezan na SAP"</string>
+ <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nije povezan na server za prijenos podataka"</string>
+ <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Spojen na ulazni uređaj"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Pov. na ur. za pris. int."</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Dij. lok. int. veze s ur."</string>
- <!-- no translation found for bluetooth_pan_profile_summary_use_for (5664884523822068653) -->
- <skip />
- <!-- no translation found for bluetooth_map_profile_summary_use_for (5154200119919927434) -->
- <skip />
- <!-- no translation found for bluetooth_sap_profile_summary_use_for (7085362712786907993) -->
- <skip />
- <!-- no translation found for bluetooth_a2dp_profile_summary_use_for (4630849022250168427) -->
- <skip />
- <!-- no translation found for bluetooth_headset_profile_summary_use_for (8705753622443862627) -->
- <skip />
- <!-- no translation found for bluetooth_opp_profile_summary_use_for (1255674547144769756) -->
- <skip />
- <!-- no translation found for bluetooth_hid_profile_summary_use_for (232727040453645139) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_accept (6163520056536604875) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_accept_all_caps (6061699265220789149) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_decline (4185420413578948140) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_will_share_phonebook (4982239145676394429) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_error_message (3748157733635947087) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_pin_error_message (8337234855188925274) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_device_down_error_message (7870998403045801381) -->
- <skip />
- <!-- no translation found for bluetooth_pairing_rejected_error_message (1648157108520832454) -->
- <skip />
- <!-- no translation found for accessibility_wifi_off (1166761729660614716) -->
- <skip />
- <!-- no translation found for accessibility_no_wifi (8834610636137374508) -->
- <skip />
- <!-- no translation found for accessibility_wifi_one_bar (4869376278894301820) -->
- <skip />
- <!-- no translation found for accessibility_wifi_two_bars (3569851234710034416) -->
- <skip />
- <!-- no translation found for accessibility_wifi_three_bars (8134185644861380311) -->
- <skip />
- <!-- no translation found for accessibility_wifi_signal_full (7061045677694702) -->
- <skip />
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Koristi za pristup internetu"</string>
+ <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Koristi za mapu"</string>
+ <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Koristi za pristup SIM-u"</string>
+ <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Koristi za zvuk medija"</string>
+ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Koristi za zvuk telefona"</string>
+ <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Koristi za prijenos fajlova"</string>
+ <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Koristi kao ulaz"</string>
+ <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Upari"</string>
+ <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"UPARI"</string>
+ <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Otkaži"</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Uparivanje odobrava pristup kontaktima i istoriji poziva kada je uspostavljeno."</string>
+ <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nije se moguće upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nije se moguće upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> zbog pogrešnog PIN-a ili pristupnog koda."</string>
+ <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ne može komunicirati sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Uređaj <xliff:g id="DEVICE_NAME">%1$s</xliff:g> je odbio uparivanje."</string>
+ <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi isključen."</string>
+ <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi nije povezan."</string>
+ <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi jedna crtica."</string>
+ <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi dvije crtice."</string>
+ <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi tri crtice."</string>
+ <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi puni signal."</string>
<string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Uklonjene aplikacije"</string>
<string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Uklonjene aplikacije i korisnici"</string>
@@ -177,27 +116,27 @@
<string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> je u potpunosti podržan"</string>
<string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> zahtjeva mrežnu vezu"</string>
<string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> nije podržan"</string>
- <!-- no translation found for tts_status_checking (5339150797940483592) -->
- <skip />
+ <string name="tts_status_checking" msgid="5339150797940483592">"Provjerava se…"</string>
<string name="tts_engine_settings_title" msgid="3499112142425680334">"Postavke za <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
<string name="tts_engine_settings_button" msgid="1030512042040722285">"Pokreni postavke programa"</string>
<string name="tts_engine_preference_section_title" msgid="448294500990971413">"Željeni program"</string>
<string name="tts_general_section_title" msgid="4402572014604490502">"Opće"</string>
- <!-- no translation found for tts_rate_entries:0 (6695494874362656215) -->
- <!-- no translation found for tts_rate_entries:1 (4795095314303559268) -->
- <!-- no translation found for tts_rate_entries:2 (8903157781070679765) -->
- <!-- no translation found for tts_rate_entries:3 (164347302621392996) -->
- <!-- no translation found for tts_rate_entries:4 (5794028588101562009) -->
- <!-- no translation found for tts_rate_entries:5 (7163942783888652942) -->
- <!-- no translation found for tts_rate_entries:6 (7831712693748700507) -->
- <!-- no translation found for tts_rate_entries:7 (5194774745031751806) -->
- <!-- no translation found for tts_rate_entries:8 (9085102246155045744) -->
+ <string-array name="tts_rate_entries">
+ <item msgid="6695494874362656215">"Veoma sporo"</item>
+ <item msgid="4795095314303559268">"Sporo"</item>
+ <item msgid="8903157781070679765">"Normalno"</item>
+ <item msgid="164347302621392996">"Brzo"</item>
+ <item msgid="5794028588101562009">"Brže"</item>
+ <item msgid="7163942783888652942">"Veoma brzo"</item>
+ <item msgid="7831712693748700507">"Ubrzano"</item>
+ <item msgid="5194774745031751806">"Veoma ubrzano"</item>
+ <item msgid="9085102246155045744">"Najbrže"</item>
+ </string-array>
<string name="choose_profile" msgid="8229363046053568878">"Odaberite profil"</string>
<string name="category_personal" msgid="1299663247844969448">"Lično"</string>
<string name="category_work" msgid="8699184680584175622">"Posao"</string>
<string name="development_settings_title" msgid="215179176067683667">"Opcije za programere"</string>
- <!-- no translation found for development_settings_enable (542530994778109538) -->
- <skip />
+ <string name="development_settings_enable" msgid="542530994778109538">"Omogući opcije za programere"</string>
<string name="development_settings_summary" msgid="1815795401632854041">"Postavi opcije za razvoj aplikacija"</string>
<string name="development_settings_not_available" msgid="4308569041701535607">"Opcije za programere nisu dostupne za ovog korisnika"</string>
<string name="vpn_settings_not_available" msgid="956841430176985598">"VPN postavke nisu dostupne za ovog korisnika"</string>
@@ -306,18 +245,12 @@
<string name="app_process_limit_title" msgid="4280600650253107163">"Ograničenje procesa u pozadini"</string>
<string name="show_all_anrs" msgid="28462979638729082">"Prikaži sve ANR-ove"</string>
<string name="show_all_anrs_summary" msgid="641908614413544127">"Prik. dijalog Aplikacija ne reagira za apl. u poz."</string>
- <!-- no translation found for force_allow_on_external (3215759785081916381) -->
- <skip />
- <!-- no translation found for force_allow_on_external_summary (3191952505860343233) -->
- <skip />
- <!-- no translation found for force_resizable_activities (8615764378147824985) -->
- <skip />
- <!-- no translation found for force_resizable_activities_summary (4508217476997182216) -->
- <skip />
- <!-- no translation found for enable_freeform_support (1461893351278940416) -->
- <skip />
- <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
- <skip />
+ <string name="force_allow_on_external" msgid="3215759785081916381">"Nametni aplikacije na vanjskoj pohrani"</string>
+ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Dozvoljava da bilo koja aplikacija bude upisana na vanjsku pohranu, bez obzira na vrijednosti manifesta."</string>
+ <string name="force_resizable_activities" msgid="8615764378147824985">"Nametni aktivnostima mijenjanje veličina"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Neka sve aktivnosti budu takve da mogu mijenjati veličinu za prikaz sa više prozora, bez obzira na prikazane vrijednosti."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore nepravilnih oblika"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogućiti podršku za eksperimentalne prozore nepravilnih oblika."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka za rezervnu kopiju radne površine"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije za računare trenutno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da promijenite ili uklonite lozinku za potpune rezervne kopije sa radne površine"</string>
@@ -339,32 +272,24 @@
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivno. Dodirnite za promjenu opcije."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"Prikažite trenutno pokrenute usluge i upravljajte njima"</string>
- <!-- no translation found for night_mode_title (2594133148531256513) -->
- <skip />
+ <string name="night_mode_title" msgid="2594133148531256513">"Noćni način rada"</string>
<string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
- <!-- no translation found for night_mode_no (9171772244775838901) -->
- <skip />
- <!-- no translation found for night_mode_yes (2218157265997633432) -->
- <skip />
+ <string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
+ <string name="night_mode_yes" msgid="2218157265997633432">"Uvijek uključeno"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatski"</string>
- <!-- no translation found for select_webview_provider_title (4628592979751918907) -->
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
<skip />
- <!-- no translation found for select_webview_provider_dialog_title (4370551378720004872) -->
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
<skip />
- <!-- no translation found for select_webview_provider_confirmation_text (6671472080671066972) -->
- <skip />
- <!-- no translation found for convert_to_file_encryption (3060156730651061223) -->
- <skip />
- <!-- no translation found for convert_to_file_encryption_enabled (2861258671151428346) -->
- <skip />
- <!-- no translation found for convert_to_file_encryption_done (7859766358000523953) -->
- <skip />
- <!-- no translation found for title_convert_fbe (1263622876196444453) -->
- <skip />
- <!-- no translation found for convert_to_fbe_warning (6139067817148865527) -->
- <skip />
- <!-- no translation found for button_convert_fbe (5152671181309826405) -->
- <skip />
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Postavljanje WebViewa"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesi WebView"</string>
+ <string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Postavljanje izabranog WebViewa je onemogućeno. Da bi se mogao koristiti, mora biti omogućen. Želite li ga omogućiti?"</string>
+ <string name="convert_to_file_encryption" msgid="3060156730651061223">"Pretvori u šifrirani fajl"</string>
+ <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pretvaranje…"</string>
+ <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fajl je već šifriran"</string>
+ <string name="title_convert_fbe" msgid="1263622876196444453">"Pretvaranje u šifrirane fajlove"</string>
+ <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Pretvori particiju sa podacima u particiju šifriranu sistemom fajlova.\n !! Upozorenje!! Ovo će izbrisati sve vaše podatke.\n Ova funkcija je u alfa fazi razvoja i možda neće ispravno raditi.\n Pritisnite \'Obriši i pretvori…\" da nastavite."</string>
+ <string name="button_convert_fbe" msgid="5152671181309826405">"Obriši i pretvori…"</string>
<string name="picture_color_mode" msgid="4560755008730283695">"Režim boja Slika"</string>
<string name="picture_color_mode_desc" msgid="1141891467675548590">"Koristi sRGB"</string>
<string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Onemogućeno"</string>
@@ -375,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Ispravka boje"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova funkcija je eksperimentalna te može utjecati na performanse."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još otprilike <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – preostalo vreme je otprilike <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pune baterije"</string>
@@ -393,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Puna"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Onemogućio administrator"</string>
<string name="home" msgid="8263346537524314127">"Početna stranica"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Još otprilike <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 333868b..beb909e 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Força permís d\'aplicacions a l\'emmagatzem. extern"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet que les aplicacions es puguin escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Força l\'ajust de la mida de les activitats"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors definits."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors definits."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activa les finestres de format lliure"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activa la compatibilitat amb les finestres de format lliure experimentals."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activa la compatibilitat amb finestres de format lliure experimentals."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contrasenya per a còpies d\'ordinador"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les còpies de seguretat d\'ordinador completes no estan protegides"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca per canviar o suprimir la contrasenya per a les còpies de seguretat completes de l\'ordinador"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desactivat"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre activat"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automàtic"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementació de WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configura la implementació de WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La implementació de WebView que has triat està desactivada i s\'ha d\'activar per utilitzar-la. Vols activar-la?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correcció del color"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Aquesta funció és experimental i pot afectar el rendiment."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Temps restant aproximat: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g>: falten aproximadament <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Plena"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Opció desactivada per l\'administrador"</string>
<string name="home" msgid="8263346537524314127">"Inici"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Fa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Temps restant: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index e219959..ad01feb 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Vynutit povolení aplikací na externím úložišti"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Každou aplikaci bude možné zapsat do externího úložiště, bez ohledu na hodnoty manifestu"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Vynutit možnost změny velikosti aktivit"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Velikost všech aktivit bude možné změnit na několik oken (bez ohledu na hodnoty manifestu)."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Umožnit změnu velikosti všech aktivit na několik oken (bez ohledu na hodnoty manifestu)"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktivovat okna s volným tvarem"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivuje podporu experimentálních oken s volným tvarem."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktivovat podporu experimentálních oken s volným tvarem"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pro zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy v počítači nejsou v současné době chráněny"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy do počítače"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Vypnuto"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Vždy zapnuto"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementace WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavte implementaci WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Vybraná implementace WebView je zakázána a nelze ji použít. Chcete ji povolit a použít?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekce barev"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Funkce je experimentální a může mít vliv na výkon."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Zbývající čas: <xliff:g id="TIME">%1$s</xliff:g> (přibližně)"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zbývá přibližně <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Zakázáno administrátorem"</string>
<string name="home" msgid="8263346537524314127">"Plocha"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"před <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Zbývající čas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 6acdcc7..e869044 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Gennemtving tilladelse til eksternt lager"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til at kunne tilpasses"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Sørger for, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tillad, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktivér vinduer i frit format"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverer understøttelse af eksperimentelle vinduer i frit format."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktivér understøttelse af eksperimentelle vinduer i frit format."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Kode til lokal sikkerhedskopi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Lokale fuldstændige sikkerhedskopieringer er i øjeblikket ikke beskyttet"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal sikkerhedskopiering"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Deaktiveret"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Altid slået til"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Konfigurer WebView-implementering"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Den valgte WebView-implementering er deaktiveret og skal aktiveres, før den kan bruges. Vil du aktivere den?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korriger farver"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Denne funktion er eksperimentel og kan påvirke ydeevnen."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%2$s</xliff:g> tilbage"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%1$s</xliff:g> tilbage"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca. <xliff:g id="TIME">%2$s</xliff:g> tilbage"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til fuldt opladet"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 5f4f60b..56d2543 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Externe Speichernutzung von Apps erlauben"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ermöglicht es jeder qualifizierten App, Daten auf externen Speicher zu schreiben, unabhängig von den Manifestwerten"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Anpassen der Größe von Aktivitäten erzwingen"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ermöglicht es, die Größe aller Aktivitäten an den Mehrfenstermodus anzupassen, unabhängig von den Manifestwerten."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Größe aller Aktivitäten an den Mehrfenstermodus anpassen, unabhängig von den Manifestwerten."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Freiform-Fenster zulassen"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Unterstützt experimentelle Freiform-Fenster."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Experimentelle Freiform-Fenster unterstützen."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop-Sicherungspasswort"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen tippen"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Deaktiviert"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Immer an"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-Implementierung"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-Implementierung festlegen"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Die ausgewählte WebView-Implementierung ist deaktiviert. Um sie nutzen zu können, muss sie aktiviert sein. Möchtest du sie aktivieren?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Farbkorrektur"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Hierbei handelt es sich um eine experimentelle Funktion. Dies kann sich auf die Leistung auswirken."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Außer Kraft gesetzt von \"<xliff:g id="TITLE">%1$s</xliff:g>\""</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Noch ca. <xliff:g id="TIME">%1$s</xliff:g> verbleibend"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – noch etwa <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Voll"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Vom Administrator deaktiviert"</string>
<string name="home" msgid="8263346537524314127">"Startseite"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Vor <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Noch <xliff:g id="ID_1">%1$s</xliff:g> verbleibend"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 826e823..e9f8661 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Να επιτρέπονται υποχρεωτικά εφαρμογές σε εξωτ.συσ."</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό χώρο αποθήκευσης, ανεξάρτητα από τις τιμές του μανιφέστου"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Αναγκαστική δυνατότητα αλλαγής μεγέθους δραστηριοτήτων"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ενεργοποιεί την υποστήριξη για πειραματικά παράθυρα ελεύθερης μορφής."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ενεργοποίηση υποστήριξης για πειραματικά παράθυρα ελεύθερης μορφής."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Εφ/κός κωδικός desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας δεν προστατεύονται αυτήν τη στιγμή"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Πατήστε για αλλαγή ή κατάργηση του κωδικού πρόσβασης για τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Ανενεργό"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Πάντα ενεργό"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Αυτόματο"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Υλοποίηση WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ορισμός υλοποίησης WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Η επιλεγμένη ενσωμάτωση WebView είναι απενεργοποιημένη και θα πρέπει να ενεργοποιηθεί για να χρησιμοποιηθεί. Θέλετε να την ενεργοποιήσετε;"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Διόρθωση χρωμάτων"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Αυτή η λειτουργία είναι πειραματική και ενδεχομένως να επηρεάσει τις επιδόσεις."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Απομένουν περίπου <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - απομένουν περίπου <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Πλήρης"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Απενεργοποιήθηκε από το διαχειριστή"</string>
<string name="home" msgid="8263346537524314127">"Αρχική οθόνη"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Πριν από <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Απομένουν <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 481cc47..668e0b2 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Make all activities resizable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Enable support for experimental freeform windows."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tap to change or remove the password for desktop full backups"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"The chosen WebView implementation is disabled and must be enabled to be used, do you wish to enable it?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Colour correction"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%1$s</xliff:g> left"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 481cc47..668e0b2 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Make all activities resizable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Enable support for experimental freeform windows."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tap to change or remove the password for desktop full backups"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"The chosen WebView implementation is disabled and must be enabled to be used, do you wish to enable it?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Colour correction"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%1$s</xliff:g> left"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 481cc47..668e0b2 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Force allow apps on external"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Make all activities resizable for multi-window, regardless of manifest values."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Enable freeform windows"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Enables support for experimental freeform windows."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Enable support for experimental freeform windows."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tap to change or remove the password for desktop full backups"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"The chosen WebView implementation is disabled and must be enabled to be used, do you wish to enable it?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Colour correction"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"This feature is experimental and may affect performance."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Approx. <xliff:g id="TIME">%1$s</xliff:g> left"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – approx. <xliff:g id="TIME">%2$s</xliff:g> left"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> until full"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 7380240..05ab073 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permisos en almacenamiento externo"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Cualquier aplicación puede escribirse en una memoria externa, independientemente de los valores del manifiesto."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forzar actividades para que cambien de tamaño"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permitir que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Habilitar ventanas de forma libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Habilita la admisión de ventanas de forma libre experimentales."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Habilitar la admisión de ventanas de forma libre experimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contraseñas"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tus copias de seguridad de escritorio no están protegidas por contraseña."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Presiona para cambiar o quitar la contraseña de las copias de seguridad completas de tu escritorio."</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Inhabilitado"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Siempre activado"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar la implementación de WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La implementación de WebView que elegiste está inhabilitada. Debes habilitarla para poder usarla. ¿Quieres hacerlo?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corrección de color"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función es experimental y puede afectar el rendimiento."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Falta <xliff:g id="TIME">%1$s</xliff:g> aproximadamente"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g>: alrededor de <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar la carga"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Cargado"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Inhabilitada por el administrador"</string>
<string name="home" msgid="8263346537524314127">"Página principal"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Falta <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 1cf51fe..5fea7554 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permiso de aplicaciones de forma externa"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hace que cualquier aplicación se pueda escribir en un dispositivo de almacenamiento externo, independientemente de los valores definidos"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forzar el ajuste de tamaño de las actividades"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite que se pueda ajustar el tamaño de todas las actividades para el modo multiventana, independientemente de los valores establecidos."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permite que se pueda ajustar el tamaño de todas las actividades para el modo multiventana, independientemente de los valores establecidos."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Habilitar ventanas de forma libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Permite utilizar ventanas de forma libre experimentales."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Habilita la opción para utilizar ventanas de forma libre experimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contraseña para copias de ordenador"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Las copias de seguridad completas de ordenador no están protegidas"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca para cambiar o quitar la contraseña de las copias de seguridad completas del escritorio"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Inhabilitado"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Siempre activado"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Establecer implementación de WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La implementación de WebView seleccionada está inhabilitada y debes habilitarla para utilizarla. ¿Quieres hacerlo?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corrección del color"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función es experimental y puede afectar al rendimiento."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Tiempo restante (aproximado): <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quedan <xliff:g id="TIME">%2$s</xliff:g> aproximadamente"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar la batería"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Inhabilitada por el administrador"</string>
<string name="home" msgid="8263346537524314127">"Inicio"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Hace <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Tiempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index c5153ff..b9d011be 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Luba rakendused välises salvestusruumis"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lubab rakendusi kirjutada välisesse salvestusruumi olenemata manifesti väärtustest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Muuda tegevuste suurused muudetavaks"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Muudab kõigi tegevuste suurused mitme aknaga vaates olenemata manifesti väärtustest muudetavaks."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Muudetakse kõigi tegevuste suurused mitme aknaga vaates muudetavaks (manifesti väärtustest olenemata)."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Luba vabas vormis aknad"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Lubatakse katseliste vabas vormis akende tugi."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Lubatakse katseliste vabavormis akende tugi."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Arvutivarunduse parool"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Täielikud arvutivarundused pole praegu kaitstud"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Puudutage täielike arvutivarunduste parooli muutmiseks või eemaldamiseks"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Keelatud"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Alati sees"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automaatne"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView\' rakendamine"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView\' rakendamise seadistamine"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Valitud WebView\' rakendamisviis on keelatud ja see tuleb kasutamiseks lubada. Kas soovite selle lubada?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Värviparandus"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"See funktsioon on katseline ja võib mõjutada toimivust."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Umbes <xliff:g id="TIME">%2$s</xliff:g> on jäänud"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Umbes <xliff:g id="TIME">%1$s</xliff:g> on jäänud"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – jäänud on umbes <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, kuni aku on täis"</string>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 1e06c6a..c1be37f 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Behartu aplikazioak onartzea kanpoko biltegian"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikazioek kanpoko memorian idatz dezakete, manifestuaren balioak kontuan izan gabe"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Behartu jardueren tamaina doitu ahal izatea"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifestuan jartzen duena jartzen duela ere, jarduera guztien tamaina doitzeko aukera ematen du, hainbat leihotan erabili ahal izan daitezen."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Eman aukera jarduera guztien tamaina doitzeko, hainbat leihotan erabili ahal izan daitezen, manifestuan jartzen duena jartzen duela ere."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Gaitu estilo libreko leihoak"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Estilo libreko leiho esperimentalak onartzen ditu."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Onartu estilo libreko leiho esperimentalak."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Tokiko babeskop. pasahitza"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Une honetan, ordenagailuko babeskopia osoak ez daude babestuta."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ordenagailuko eduki guztiaren babeskopia egiteko erabiltzen den pasahitza aldatzeko edo kentzeko, sakatu hau"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desgaituta"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Beti aktibatuta"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatikoa"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Desgaituta dago aukeratu den WebView inplementazioa. Erabili nahi izanez gero, gaitu egin behar duzu. Gaitu nahi al duzu?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kolore-zuzenketa"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Eginbidea esperimentala da eta eragina izan dezake funtzionamenduan."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"<xliff:g id="TIME">%1$s</xliff:g> inguru guztiz kargatu arte"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> inguru. <xliff:g id="TIME">%2$s</xliff:g> geratzen d(ir)a"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Beteta"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administratzaileak desgaitu du"</string>
<string name="home" msgid="8263346537524314127">"Hasierako pantaila"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Duela <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> guztiz kargatu arte"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index e023f247..fc4cd7d 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"اجازه اجباری به برنامههای دستگاه ذخیره خارجی"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"بدون توجه به مقادیر مانیفست، هر برنامهای را برای نوشتن در حافظه خارجی واجد شرایط میکند"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"اجبار فعالیتها به قابل تغییر اندازه بودن"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"بدون درنظر گرفتن مقادیر مانیفست، همه فعالیتها را برای چندپنجره قابل تغییر اندازه میکند."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"بدون توجه به مقادیر مانیفست، اندازه همه فعالیتها برای حالت چند پنجرهای میتواند تغییر کند."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"فعال کردن پنجرههای آزاد"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"پشتیبانی برای پنجرههای آزاد آزمایشی را امکانپذیر میکند"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"فعال کردن پشتیبانی برای پنجرههای آزاد آزمایشی."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"گذرواژه پشتیبانگیری محلی"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"پشتیبانگیری کامل رایانه درحال حاضر محافظت نمیشود"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"برای تغییر یا حذف گذرواژه برای نسخههای پشتیبان کامل رایانهای ضربه بزنید"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"غیرفعال است"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"همیشه روشن"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"اجرای WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تنظیم اجرای WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"پیادهسازی WebView انتخابشده غیرفعال شده است و برای استفاده شدن باید فعال شود؛ میخواهید آن را فعال کنید؟"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"تصحیح رنگ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"این قابلیت آزمایشی است و ممکن است عملکرد را تحت تأثیر قرار دهد."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"توسط <xliff:g id="TITLE">%1$s</xliff:g> لغو شد"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"تقریباً <xliff:g id="TIME">%1$s</xliff:g> باقی مانده است"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - تقریباً <xliff:g id="TIME">%2$s</xliff:g> باقی مانده است"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"پر"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"سرپرست آن را غیرفعال کرده است"</string>
<string name="home" msgid="8263346537524314127">"صفحه اصلی"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی مانده است"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index c4f572c..34309c1 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Salli aina ulkoinen tallennus"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mahdollistaa sovellusten tallentamisen ulkoiseen tall.tilaan luettelosta riippumatta"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Pakota kaikki toiminnot hyväksymään koon muutos"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pakottaa kaikki toiminnot hyväksymään koon muuttamisen rinnakkaisnäkymään luettelon arvoista riippumatta."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Pakota kaikki toiminnot hyväksymään koon muuttaminen usean ikkunan tilassa luettelon arvoista riippumatta."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ota käyttöön vapaamuotoiset ikkunat"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ottaa käyttöön kokeellisten vapaamuotoisten ikkunoiden tuen."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ota kokeellisten vapaamuotoisten ikkunoiden tuki käyttöön."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Varmuuskop. salasana"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tietokoneen kaikkien tietojen varmuuskopiointia ei ole tällä hetkellä suojattu"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Vaihda tai poista tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla."</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Ei käytössä"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Aina käytössä"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automaattinen"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-käyttöönotto"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Määritä WebView-käyttöönotto"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Valittu WebView-käyttöönotto on poistettu käytöstä. Haluatko ottaa sen käyttöön?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Värikorjaus"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Tämä ominaisuus on kokeellinen ja voi vaikuttaa suorituskykyyn."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Tämän ohittaa <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Noin <xliff:g id="TIME">%1$s</xliff:g> jäljellä"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – noin <xliff:g id="TIME">%2$s</xliff:g> jäljellä"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Täynnä"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Järjestelmänvalvojan käytöstä poistama"</string>
<string name="home" msgid="8263346537524314127">"Aloitusnäyttö"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> sitten"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> jäljellä"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index f888ec8..1181c2a3 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forcer l\'autor. d\'applis sur stockage externe"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet enreg. d\'applis sur espace stockage externe"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forcer les activités à être redimensionnables"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activer les fenêtres de forme libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Active la compatibilité avec les fenêtres de forme libre expérimentales."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activer la compatibilité avec les fenêtres de forme libre expérimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Touchez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur ordinateur."</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Désactivé"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Toujours actif"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Mise en œuvre WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Définir la mise en œuvre WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La mise en œuvre WebView sélectionnée est désactivée. Vous devez l\'activer pour l\'utiliser. Souhaitez-vous l\'activer?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correction des couleurs"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Cette fonctionnalité est expérimentale et peut toucher les performances."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> %% – Temps restant : environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> %% (chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Pleine"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Désactivé par l\'administrateur"</string>
<string name="home" msgid="8263346537524314127">"Accueil"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Durée restante :<xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index dfc71f1..0639f1f 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forcer disponibilité stockage externe pour applis"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rend possible enregistrement de toute appli sur espace stockage externe, indépendamment valeurs fichier manifeste."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forcer possibilité de redimensionner les activités"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permettre de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activer les fenêtres de forme libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Active la compatibilité avec les fenêtres de forme libre expérimentales."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activer la compatibilité avec les fenêtres de forme libre expérimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Désactivé"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Toujours activé"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Mise en œuvre WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Définir la mise en œuvre WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"La mise en œuvre WebView sélectionnée est désactivée. Vous devez l\'activer pour l\'utiliser. Souhaitez-vous l\'activer ?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correction couleur"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Cette fonctionnalité est expérimentale et peut affecter les performances."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Il reste environ <xliff:g id="TIME">%1$s</xliff:g>."</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – Temps restant : <xliff:g id="TIME">%2$s</xliff:g> environ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> (chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>)"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"pleine"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Désactivé par l\'administrateur"</string>
<string name="home" msgid="8263346537524314127">"Accueil"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Il y a <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Il reste <xliff:g id="ID_1">%1$s</xliff:g>."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index 20985bd..5622d63 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forzar permiso de aplicacións de forma externa"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Fai que calquera aplicación se poida escribir nun almacenamento externo, independentemente dos valores expresados"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forzar o axuste do tamaño das actividades"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite axustar o tamaño de todas as actividades para o modo de varias ventás, independentemente dos valores definidos."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permite axustar o tamaño de todas as actividades para o modo de varias ventás, independentemente dos valores definidos."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activar ventás de forma libre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activa a compatibilidade con ventás de forma libre experimentais."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activa a compatibilidade con ventás de forma libre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contrasinal para copias"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"As copias de seguridade de ordenador completas non están protexidas"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toca para cambiar ou eliminar o contrasinal para as copias de seguranza completas do escritorio"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desactivado"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre activada"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Definir implementación de WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementación de WebView escollida está desactivada e, para poder usala, debe estar activada. Queres activala?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corrección da cor"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta función é experimental e pode afectar ao rendemento."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Duración aproximada de <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - faltan aproximadamente <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar a carga"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Completa"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desactivado polo administrador"</string>
<string name="home" msgid="8263346537524314127">"Inicio"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Hai <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Tempo restante: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 18917e0..2c1990f 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"બાહ્ય પર એપ્લિકેશનોને મંજૂરી આપવાની ફરજ પાડો"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ એપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"તમામ પ્રવૃત્તિઓને મલ્ટી-વિંડો માટે ફરીથી કદ બદલી શકે તેવી બનાવે છે, મેનીફેસ્ટ મુલ્યોને ધ્યાનમાં લીધા સિવાય."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"મૅનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, તમામ પ્રવૃત્તિઓને મલ્ટી-વિંડો માટે ફરીથી કદ બદલી શકે તેવી બનાવો."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ફ્રિફોર્મ વિંડોઝ સક્ષમ કરો"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"પ્રાયોગિક ફ્રિફોર્મ વિંડોઝ માટે સમર્થનને સક્ષમ કરે છે."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"પ્રાયોગિક ફ્રિફોર્મ વિંડોઝ માટે સમર્થનને સક્ષમ કરો."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ડેસ્કટૉપ બેકઅપ પાસવર્ડ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ હાલમાં સુરક્ષિત નથી"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટૅચ કરો"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"અક્ષમ કરેલ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"હંમેશાં ચાલુ"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"સ્વચલિત"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView અમલીકરણ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView અમલીકરણ સેટ કરો"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"પસંદ કરેલ WebView અમલીકરણ અક્ષમ કરેલ છે અને ઉપયોગ કરવા માટે સક્ષમ કરવું આવશ્યક છે, શું તમે તેને સક્ષમ કરવા માગો છો?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"રંગ સુધારણા"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"આ સુવિધા પ્રાયોગિક છે અને કામગીરી પર અસર કરી શકે છે."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"અંદાજે. <xliff:g id="TIME">%1$s</xliff:g> બાકી"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - આશરે <xliff:g id="TIME">%2$s</xliff:g> બાકી"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"સંપૂર્ણ થવામાં <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"પૂર્ણ"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"વ્યવસ્થાપક દ્વારા અક્ષમ"</string>
<string name="home" msgid="8263346537524314127">"હોમ"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> પહેલાં"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> બાકી"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 32b2814..7deb05c 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ऐप्स को बाहरी मेमोरी पर बाध्य करें"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"इससे कोई भी ऐप मेनिफेस्ट मान अनदेखा करके, बाहरी मेमोरी पर लिखने योग्य बन जाता है"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"आकार बदले जाने के लिए गतिविधियों को बाध्य करें"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"एकाधिक-विंडो के लिए सभी गतिविधियों के आकार को बदले जाने योग्य बनाता है, चाहे मेनिफेस्ट मान कुछ भी हों."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"सभी गतिविधियों को एकाधिक विंडो के लिए आकार बदलने योग्य बनाएं, चाहे मेनिफेस्ट मान कुछ भी हों."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"फ़्रीफ़ॉर्म विंडो सक्षम करें"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ़्रीफ़ॉर्म विंडो का समर्थन सक्षम करती है."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रयोगात्मक फ़्रीफ़ॉर्म विंडो का समर्थन सक्षम करें."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बैकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप पूर्ण बैकअप वर्तमान में सुरक्षित नहीं हैं"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉप के पूर्ण बैकअप का पासवर्ड बदलने या निकालने के लिए टैप करें"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"अक्षम"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"हमेशा चालू"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट करें"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"चुना गया WebView कार्यान्वयन अक्षम है और उसे उपयोग करने के लिए सक्षम किया जाना आवश्यक है, क्या आप उसे सक्षम करना चाहते हैं?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"रंग सुधार"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"यह सुविधा प्रायोगिक है और निष्पादन को प्रभावित कर सकती है."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"लगभग <xliff:g id="TIME">%2$s</xliff:g> शेष"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"लगभग <xliff:g id="TIME">%1$s</xliff:g> शेष"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - लगभग <xliff:g id="TIME">%2$s</xliff:g> शेष"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूरी होने तक"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 37b5363..ca58584 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Prisilno dopusti aplikacije u vanjskoj pohrani"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o manifestu"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Nametni mogućnost promjene veličine za aktivnosti"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veličina svih aktivnosti može se mijenjati za više prozora, neovisno o vrijednostima manifesta."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogući mijenjanje veličine svih aktivnosti za više prozora, neovisno o vrijednostima manifesta."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore slobodnog oblika"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogućuje podršku za eksperimentalne prozore slobodnog oblika."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogući podršku za eksperimentalne prozore slobodnog oblika."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Zaporka sigurnosne kopije"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije na stolnom računalu trenutačno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da biste promijenili ili uklonili zaporku za potpune sigurnosne kopije na računalu"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Uvijek uključeno"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatska"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementacija WebViewa"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Postavi implementaciju WebViewa"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Odabrana implementacija WebViewa onemogućena je i morate je omogućiti da biste je mogli upotrebljavati. Želite li je omogućiti?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcija boje"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova je značajka eksperimentalna i može utjecati na performanse."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Premošćeno postavkom <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Još približno <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – još približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 9113ab3..365c409 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Külső tárhely alkalmazásainak engedélyezése"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lehetővé teszi, hogy külső tárhelyre lehessen írni"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tevékenységek átméretezésének kényszerítése"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Lehetővé teszi, hogy az összes tevékenység átméretezhető legyen a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Legyen az összes tevékenység átméretezhető a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Szabad formájú ablakok engedélyezése"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Engedélyezi a kísérleti jellegű, szabad formájú ablakok támogatását."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Kísérleti, szabad formájú ablakok támogatásának engedélyezése."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Asztali mentés jelszava"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Az asztali teljes biztonsági mentések jelenleg nem védettek."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Koppintson ide az asztali teljes mentések jelszavának módosításához vagy eltávolításához"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Kikapcsolva"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Mindig bekapcsolva"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatikus"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-megvalósítás"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-megvalósítás beállítása"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A kiválasztott WebView-megvalósítás le van tiltva, a használathoz viszont engedélyezni kell. Szeretné engedélyezni?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Színkorrekció"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ez egy kísérleti funkció, és hatással lehet a teljesítményre."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Felülírva erre: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kb. <xliff:g id="TIME">%2$s</xliff:g> van hátra"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kb. <xliff:g id="TIME">%1$s</xliff:g> van hátra"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – kb. <xliff:g id="TIME">%2$s</xliff:g> van hátra"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a teljes töltöttség eléréséig"</string>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index 2baa160..b210698 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Միշտ թույլատրել ծրագրեր արտաքին պահեստում"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Թույլ է տալիս պահել հավելվածը արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Ստիպել, որ ակտիվությունների չափերը լինեն փոփոխելի"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ակտիվացնել կամայական ձևի պատուհանները"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ակտիվացնում է կամայական ձևի փորձնական պատուհանների աջակցումը:"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Միացնել ազատ ձևի փորձնական պատուհանների աջակցումը:"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Հպեք՝ աշխատասեղանի ամբողջական պահուստավորման գաղտնաբառը փոխելու կամ հեռացնելու համար"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Անջատված"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Միշտ միացված"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Ավտոմատ"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-ի իրականացում"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ընտրեք WebView-ի իրականացումը"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"WebView-ի իրականացման ընտրված եղանակն անջատված է և օգտագործելու համար պետք է նախ միացվի: Միացնե՞լ:"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Գունային կարգաբերում"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Սա փորձնական գործառույթ է և կարող է ազդել աշխատանքի վրա:"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Մնացել է մոտ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - մնաց մոտավորապես <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Լիցքավորված"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Կասեցված է ադմինիստրատորի կողմից"</string>
<string name="home" msgid="8263346537524314127">"Գլխավոր էջ"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> առաջ"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Մնացել է <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 1a47576..33e869c 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Paksa izinkan aplikasi di eksternal"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksterna"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktivitas agar ukurannya dapat diubah"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Membuat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Buat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktifkan jendela berformat bebas"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Mengaktifkan dukungan untuk jendela eksperimental berformat bebas."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktifkan dukungan untuk jendela eksperimental berformat bebas."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Sandi cadangan desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Saat ini cadangan desktop penuh tidak dilindungi"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ketuk guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Dinonaktifkan"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Selalu aktif"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Otomatis"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Penerapan WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Setel penerapan WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Implementasi WebView yang dipilih telah dinonaktifkan, dan harus diaktifkan agar dapat digunakan. Ingin mengaktifkannya?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Koreksi warna"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Fitur ini bersifat eksperimental dan dapat memengaruhi kinerja."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kira-kira tersisa <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira tersisa. <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sampai penuh"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dinonaktifkan oleh administrator"</string>
<string name="home" msgid="8263346537524314127">"Layar Utama"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> lalu"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Tersisa <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index 558f7bc..b79dcf8 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Þvinga fram leyfi forrita í ytri geymslu"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gerir hvaða forriti sem er kleift að skrifa í ytri geymslu, burtséð frá gildum í upplýsingaskrá"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Þvinga breytanlega stærð virkni"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gerir stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gera stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Virkja glugga með frjálsu sniði"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Kveikir á stuðningi við glugga með frjálsu sniði á tilraunastigi."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Virkja stuðning við glugga með frjálsu sniði á tilraunastigi."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Aðgangsorð tölvuafritunar"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ýttu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Óvirkt"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Alltaf kveikt"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Sjálfvirkt"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Innleiðing WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stilla innleiðingu WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Slökkt er á valinni innleiðingu WebView. Kveikja þarf á henni til að hægt sé að nota hana. Viltu gera það?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Litaleiðrétting"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Þessi eiginleiki er á tilraunastigi og getur haft áhrif á frammistöðu."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Um það bil <xliff:g id="TIME">%1$s</xliff:g> eftir"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – u.þ.b. <xliff:g id="TIME">%2$s</xliff:g> eftir"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> í fulla hleðslu"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullhlaðin"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Stjórnandi gerði óvirkt"</string>
<string name="home" msgid="8263346537524314127">"Heim"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Fyrir <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> eftir"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 24564c1..d5753c4 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forza autorizzazione app su memoria esterna"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rende l\'app idonea all\'installaz. su mem. esterna, senza considerare i valori manifest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Imponi formato modificabile alle attività"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Rende il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Rendi il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Attiva finestre a forma libera"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Attiva il supporto per le finestre a forma libera sperimentali."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Attiva il supporto delle finestre a forma libera sperimentali."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Password di backup desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"I backup desktop completi non sono attualmente protetti."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tocca per modificare o rimuovere la password per i backup desktop completi"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Disattivato"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre attivo"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatico"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementazione di WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Imposta l\'implementazione di WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"L\'implementazione di WebView selezionata non è attiva e deve essere attivata per poterla utilizzare. Vuoi attivarla?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correzione del colore"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Questa funzione è sperimentale e potrebbe influire sulle prestazioni."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Circa <xliff:g id="TIME">%1$s</xliff:g> rimanenti"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tempo rimanente: <xliff:g id="TIME">%2$s</xliff:g> circa"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla carica completa"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Carica"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Disattivata dall\'amministratore"</string>
<string name="home" msgid="8263346537524314127">"Home page"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> fa"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> rimanenti"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 5dea0a2..ee2588f 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"אילוץ הרשאה של אפליקציות באחסון חיצוני"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"אלץ יכולת קביעת גודל של הפעילויות"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"מאפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"אפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"הפעל את האפשרות לשנות את הגודל והמיקום של החלונות"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"מפעיל תמיכה בתכונה הניסיונית של שינוי הגודל והמיקום של החלונות."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"הפעל תמיכה בתכונה הניסיונית של שינוי הגודל והמיקום של החלונות."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"סיסמת גיבוי מקומי"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"הקש כדי לשנות או להסיר את הסיסמה לגיבויים מלאים בשולחן העבודה"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"מושבת"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"פועל תמיד"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"באופן אוטומטי"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"יישום WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"הגדרת יישום WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"יישום ה-WebView שנבחר מושבת, ויש להפעיל אותו כדי להשתמש בו. האם ברצונך להפעיל אותו?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"תיקון צבע"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"תכונה זו היא ניסיונית ועשויה להשפיע על הביצועים."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"נשארו <xliff:g id="TIME">%1$s</xliff:g> בערך"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> בקירוב עד לסיום"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> עד למילוי"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"מלא"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"הושבת על ידי מנהל המערכת"</string>
<string name="home" msgid="8263346537524314127">"דף הבית"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"לפני <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"נשארו <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index eb7f8af..67bf4b0 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"外部ストレージへのアプリの書き込みを許可"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"アクティビティをサイズ変更可能にする"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようになります。"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようにします。"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"フリーフォーム ウィンドウの有効化"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"テスト段階のフリーフォーム ウィンドウのサポートを有効にします。"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"外部のフリーフォーム ウィンドウのサポートを有効にします。"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"PCバックアップパスワード"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"デスクトップのフルバックアップは現在保護されていません"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"無効"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"常にON"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView の実装"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView の実装の設定"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"選択した WebView の実装は無効になっていますが、使用するには有効にする必要があります。有効にしますか?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"色補正"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"この機能は試験運用機能であり、パフォーマンスに影響することがあります。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g>によって上書き済み"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"あと約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 残り約<xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - フル充電まで<xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -316,8 +319,6 @@
<skip />
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"管理者によって無効にされています"</string>
<string name="home" msgid="8263346537524314127">"ホーム"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"あと <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 540dc81..f441fa0 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"აპების დაშვება გარე მეხსიერებაში"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"აპები ჩაიწერ. გარე მეხს.-ზე აღწ. ფაილის მნიშვნ. მიუხედ."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ზომაცვლადი აქტივობების იძულება"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"მანიფესტის მნიშვნელობების მიუხედავად, ყველა აქტივობას მრავალი ფანჯრის რეჟიმისთვის ზომაცვლადად აქცევს."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"მანიფესტის მნიშვნელობების მიუხედავად, მრავალი ფანჯრის რეჟიმისთვის ყველა აქტივობის ზომაცვლადად გადაქცევა."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"თავისუფალი ფორმის მქონე ფანჯრების ჩართვა"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ჩართავს თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტულ ფუნქციას"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტული ფუნქციის ჩართვა."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"დესკტოპის სარეზერვო ასლის პაროლი"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"გამორთულია"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ყოველთვის ჩართული"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ავტომატური"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView რეალიზაცია"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView რეალიზაციის დაყენება"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"არჩეული WebView რეალიზაცია გათიშულია და გამოყენებამდე უნდა ჩაირთოს. გსურთ მისი ჩართვა?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ფერის კორექცია"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ეს ფუნქცია საცდელია და შეიძლება გავლენა იქონიოს შესრულებაზე."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"უკუგებულია <xliff:g id="TITLE">%1$s</xliff:g>-ის მიერ"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"დარჩენილია დაახლოებით <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"დაახლ. <xliff:g id="LEVEL">%1$s</xliff:g> დარჩენილია <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> სრულ დატენვამდე"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"ბატარეა დატენილია"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"გათიშულია ადმინისტრატორის მიერ"</string>
<string name="home" msgid="8263346537524314127">"მთავარი"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"გავიდა <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"დარჩენილია <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 7f59d97..fb5ab12 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Сыртқыда қолданбаларға мәжбүрлеп рұқсат ету"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест мәндеріне қарамастан кез келген қолданбаны сыртқы жадқа жазуға жарамды етеді"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Әрекеттерді өлшемін өзгертуге болатын етуге мәжбүрлеу"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест мәндеріне қарамастан барлық әрекеттерді бірнеше терезе үшін өлшемін өзгертуге болатын етеді."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Манифест мәндеріне қарамастан барлық әрекеттерді бірнеше терезе үшін өлшемін өзгертуге болатын етеді."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Еркін пішіндегі терезелерді қосу"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Эксперименттік еркін пішіндегі терезелерді қолдауды қосады."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Эксперименттік еркін терезелерді қолдауды қосу."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Компьютер үстелінің сақтық көшірмесі"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Жұмыс үстелінің сақтық көшірмелері қазір қорғалмаған"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Үстелдік компьютердің толық сақтық көшірмелерінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Өшірілген"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Әрқашан қосулы"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Aвтоматты"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ендіру"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ендіруін орнату"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Таңдалған веб-көріністі енгізу өшірілген және пайдалану үшін оны қосу керек. Оны қосу керек пе?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Түсті түзету"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бұл мүмкіндік эксперименттік болып табылады және өнімділікке әсер етуі мүмкін."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Шамамен <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - шамамен <xliff:g id="TIME">%2$s</xliff:g> қалды"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - толғанша <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Толық"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Әкімші өшірген"</string>
<string name="home" msgid="8263346537524314127">"Негізгі бет"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> бұрын"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> қалды"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index a949538..c1946c4 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"បង្ខំឲ្យអនុញ្ញាតកម្មវិធីលើឧបករណ៍ផ្ទុកខាងក្រៅ"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"កំណត់ឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុផ្ទាំងវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេសឡើយ។"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"កំណត់ឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុផ្ទាំងវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេស។"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"បើកដំណើរការផ្ទាំងវិនដូទម្រង់សេរី"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"បើកដំណើរការគាំទ្រផ្ទាំងវិនដូទម្រង់សេរីសាកល្បង"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"បើកដំណើរការគាំទ្រផ្ទាំងវិនដូទម្រង់សេរីសាកល្បង"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ពាក្យសម្ងាត់បម្រុងទុកលើផ្ទៃតុ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ការបម្រុងទុកពេញលេញលើផ្ទៃតុបច្ចុប្បន្នមិនត្រូវបានការពារទេ។"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ប៉ះដើម្បីប្ដូរ ឬយកពាក្យសម្ងាត់ចេញសម្រាប់ការបម្រុងទុកពេញលេញលើកុំព្យូទ័រ"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"បានបិទ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"បើកជានិច្ច"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ស្វ័យប្រវត្តិ"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"ការប្រតិបត្តិ WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"កំណត់ការប្រតិបត្តិ WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ការប្រតិបត្តិការ WebView ដែលបានជ្រើសត្រូវបានបិទដំណើរការ ប៉ុន្តែអ្នកត្រូវបើកដំណើរការវាដើម្បីប្រើ តើអ្នកចង់បើកដំណើរការវាដែរឬទេ?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ការកែពណ៌"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"លក្ខណៈនេះគឺជាការពិសោធន៍ ហើយអាចប៉ះពាល់ការអនុវត្ត។"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"បដិសេធដោយ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"នៅសល់ប្រហែល <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - នៅសល់ប្រហែល <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> រហូតដល់ពេញ"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"ពេញ"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រង"</string>
<string name="home" msgid="8263346537524314127">"ដើម"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> មុន"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"នៅសល់ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index bfe0c1e..a6acd17 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ಬಾಹ್ಯವಾಗಿ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಒತ್ತಾಯವಾಗಿ ಅನುಮತಿಸಿ"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ಗೆ ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡುತ್ತದೆ."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡಿ."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ಪ್ರಾಯೋಗಿಕ ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ಪ್ರಾಯೋಗಿಕ ಫ್ರೀಫಾರ್ಮ್ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ಡೆಸ್ಕ್ಟಾಪ್ ಬ್ಯಾಕಪ್ ಪಾಸ್ವರ್ಡ್"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ಡೆಸ್ಕ್ಟಾಪ್ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್ಗಳನ್ನು ಪ್ರಸ್ತುತ ರಕ್ಷಿಸಲಾಗಿಲ್ಲ"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ಡೆಸ್ಕ್ಟಾಪ್ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್ಗಳಿಗೆ ಪಾಸ್ವರ್ಡ್ ಬದಲಾಯಿಸಲು ಅಥವಾ ತೆಗೆದುಹಾಕಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ಯಾವಾಗಲೂ ಆನ್"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ಸ್ವಯಂಚಾಲಿತ"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿಸಿ"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ಆಯ್ಕೆಮಾಡಲಾದ WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಮತ್ತು ಬಳಸಲು ಸಕ್ರಿಯಗೊಳಿಸಬೇಕಾಗಿದೆ, ಇದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ನೀವು ಬಯಸುತ್ತೀರಾ?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ಇದು ಪ್ರಾಯೋಗಿಕ ವೈಶಿಷ್ಟ್ಯವಾಗಿದೆ. ಕಾರ್ಯಕ್ಷಮತೆ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರಬಹುದು."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"ಸುಮಾರು <xliff:g id="TIME">%2$s</xliff:g> ಉಳಿದಿದೆ"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ಸುಮಾರು <xliff:g id="TIME">%1$s</xliff:g> ಉಳಿದಿದೆ"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"ಸುಮಾರು <xliff:g id="LEVEL">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g> ಉಳಿದಿದೆ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ಪೂರ್ಣವಾಗುವವರೆಗೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 5d1176a..c8bb2e6 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"외부에서 앱 강제 허용"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"매니페스트 값에 관계없이 앱을 외부 저장소에 작성"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"활동의 크기가 조정 가능하도록 설정"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"자유 형식 창 사용"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"자유 형식 창(베타) 지원 사용"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"자유 형식 창 지원 사용"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"데스크톱 백업 비밀번호"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"데스크톱 전체 백업에 비밀번호가 설정되어 있지 않음"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 탭하세요."</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"사용 안함"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"항상 사용"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"자동"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 구현"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView 구현 설정"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"선택한 WebView 구현이 사용 중지되어 있습니다. 사용하려면 사용 설정해야 합니다. 사용 설정하시겠습니까?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"색보정"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"실험실 기능이며 성능에 영향을 줄 수 있습니다."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"약 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 대략 <xliff:g id="TIME">%2$s</xliff:g> 남음"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"충전 완료"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"관리자가 사용 중지함"</string>
<string name="home" msgid="8263346537524314127">"홈"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> 전"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> 남음"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index f0867f5..6f158c0 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Тышкы сактагычка сактоого уруксат берүү"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Аракеттердин өлчөмүн өзгөртүүнү мажбурлоо"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест маанилерине карабастан бардык аракеттерди мульти-терезеге өлчөмү өзгөртүлгүдөй кылат."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Манифест маанилерине карабастан бардык аракеттерди мульти-терезеге өлчөмү өзгөртүлгүдөй кылуу."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Эркин формадагы терезелерди түзүүнү иштетүү"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Эркин формадагы терезелерди түзүү боюнча сынамык функцияны иштетүү"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Эркин формадагы терезелерди түзүү боюнча сынамык функцияны иштетүү."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Компүтердеги бэкаптын сырсөзү"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Компүтердеги толук бэкап учурда корголгон эмес"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Иш тактасынын камдалган сырсөзүн өзгөртүү же алып салуу үчүн таптап коюңуз"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Өчүрүлгөн"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Ар дайым күйгүзүлгөн"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматтык"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView аткарылышы"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView аткарылышын коюу"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"WebView кызматын пайдалануу үчүн аны иштетүү керек. Иштетесизби?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Түсүн тууралоо"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бул сынамык мүмкүнчүлүк болгондуктан, иштин майнаптуулугуна таасир этиши мүмкүн."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"<xliff:g id="TIME">%1$s</xliff:g>-чакты калды"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - болжол менен <xliff:g id="TIME">%2$s</xliff:g> саат калды"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> толгончо"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Толук"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Администратор өчүрүп койгон"</string>
<string name="home" msgid="8263346537524314127">"Башкы бет"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> мурун"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> калды"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 1419466..7664212 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ບັງຄັບອະນຸຍາດແອັບຢູ່ພາຍນອກ"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ເຮັດໃຫ້ທຸກແອັບມີສິດໄດ້ຮັບການຂຽນໃສ່ບ່ອນຈັດເກັບພາຍນອກ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າທີ່ຈະແຈ້ງ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ບັງຄັງໃຫ້ກິດຈະກຳປ່ຽນຂະໜາດໄດ້"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ເຮັດໃຫ້ທຸກກິດຈະກຳປ່ຽນຂະໜາດໄດ້ສຳລັບຫຼາຍໜ້າຕ່າງ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າທີ່ຈະແຈ້ງ."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ເຮັດໃຫ້ທຸກກິດຈະກຳສາມາດປັບຂະໜາດໄດ້ສຳລັບຫຼາຍໜ້າຈໍ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າທີ່ຈະແຈ້ງ."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ເປີດໃຊ້ໜ້າຕ່າງຮູບແບບອິດສະຫຼະ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ເປີດໃຊ້ການຮອງຮັບໜ້າຕ່າງຮູບແບບອິດສະຫຼະທີ່ທົດລອງໃຊ້."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ເປີດໃຊ້ການຮອງຮັບໜ້າຈໍຮູບແບບອິດສະຫຼະແບບທົດລອງ."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັກສະທັອບ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບຍັງບໍ່ໄດ້ຮັບການປ້ອງກັນໃນເວລານີ້"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບ"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"ປິດໃຊ້ງານແລ້ວ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ເປີດຕະຫຼອດ"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ອັດຕະໂນມັດ"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ຕັ້ງການຈັດຕັ້ງປະຕິບັດ WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ການຈັດຕັ້ງປະຕິບັດ WebView ທີ່ເລືອກຖືກປິດນຳໃຊ້, ແລະຕ້ອງຖືກເປີດນຳໃຊ້, ທ່ານຕ້ອງການເປີດນຳໃຊ້ມັນບໍ?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ການປັບແຕ່ງສີ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ຄຸນສົມບັດນີ້ກຳລັງຢູ່ໃນການທົດລອງແລະອາດມີຜົນຕໍ່ປະສິດທິພາບ."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"ຖືກແທນໂດຍ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ຍັງເຫຼືອປະມານ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ເຫຼືອປະມານ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈຶ່ງຈະເຕັມ"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"ເຕັມ"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ຖືກປິດໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
<string name="home" msgid="8263346537524314127">"ໜ້າຫຼັກ"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> ກ່ອນນີ້"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"ຍັງເຫຼືອ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 3f5493d..c730dc0 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Priverstinai leisti programas išorinėje atmintin."</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Vis. pr. gal. įr. į vid. saug. nepais. apr. vert."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Priv. nust., kad veiksm. b. g. atl. kelių d. lang."</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Nustatoma, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Nustatyti, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Įgalinti laisvos formos langus"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Įgalinamas eksperimentinių laisvos formos langų palaikymas."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Įgalinti eksperimentinių laisvos formos langų palaikymą."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Viet. atsrg. kop. slapt."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Jei norite pakeisti ar pašalinti visų stalinio kompiuterio atsarginių kopijų slaptažodį, palieskite"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Išjungta"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Visada įjungta"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatinė"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"„WebView“ diegimas"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"„WebView“ diegimo nustatymas"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Pasirinktas „WebView“ diegimas išjungtas ir jį būtina įgalinti, kad būtų galima naudoti. Ar norite jį įgalinti?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Spalvų taisymas"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ši funkcija yra eksperimentinė ir ji gali turėti įtakos našumui."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Liko maždaug <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko maždaug <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> iki visiško įkrovimo"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Visiškai įkrautas"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Išjungė administratorius"</string>
<string name="home" msgid="8263346537524314127">"Pagrindinis ekranas"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Prieš <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Liko <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index dd70703..65e4cff 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Lietotņu piespiedu atļaušana ārējā krātuvē"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Pielāgot darbības"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pielāgo visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Pielāgot visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Iespējot brīvās formas logus"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Iespējo eksperimentālo brīvās formas logu atbalstu."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Iespējot eksperimentālo brīvās formas logu atbalstu."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Datora dublējuma parole"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem datora dublējumiem."</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Atspējots"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Vienmēr ieslēgts"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automātiski"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ieviešana"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Iestatīt WebView ieviešanu"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Izvēlētā WebView ieviešana ir atspējota, un tā ir jāiespējo, lai to varētu izmantot. Vai vēlaties to iespējot?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Krāsu korekcija"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Šī funkcija ir eksperimentāla un var ietekmēt veiktspēju."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Atlikušais laiks: aptuveni <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> — aptuvenais atlikušais laiks: <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Pilns"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Atspējojis administrators"</string>
<string name="home" msgid="8263346537524314127">"Sākums"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Pirms šāda laika: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Atlikušais laiks: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 5bdfd01..4576f3a 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Принуд. дозволете апликации на надворешна меморија"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Запишува апл. во надв.меморија, незав. од манифест"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Принуди ги активностите да ја менуваат големината"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ги прави сите активности да бидат со променлива големина за мултипрозорец, без разлика на вредностите на манифестот."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Направете сите активности да бидат со променлива големина за повеќе прозорци, без разлика на вредностите на манифестот."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Овозможи прозорци со слободна форма"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Овозможува поддршка за експериментални прозорци со слободна форма."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Овозможи поддршка за експериментални прозорци со слободна форма."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Резервна лозинка за работна површина"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Целосни резервни копии на работната површина кои во моментов не се заштитени"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Допрете за да се промени или отстрани лозинката за целосни резервни копии на работната површина"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Оневозможено"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Секогаш вклучено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматски"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Воведување WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Поставете воведување WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Избраната примена на WebView е оневозможена, а за да се користи, мора да се овозможи. Дали сакате да ја овозможите?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Корекција на боја"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Функцијата е експериментална и може да влијае на изведбата."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Преостанаа прибл. <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Преостанаа прибл. <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – преостанува приближно <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до целосно полна"</string>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 38b4771..180d615 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ബാഹ്യമായതിൽ നിർബന്ധിച്ച് അനുവദിക്കുക"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"വലിപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ പ്രവർത്തനങ്ങളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലിപ്പം മാറ്റുന്നു."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ ആക്ടിവിറ്റികളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലിപ്പം മാറ്റുക."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"ഫ്രീഫോം വിൻഡോകൾ പ്രവർത്തനക്ഷമമാക്കുക"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"പരീക്ഷണാത്മക ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുന്നു."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"പരീക്ഷണാത്മക ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുക."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ഡെസ്ക്ടോപ്പ് ബാക്കപ്പ് പാസ്വേഡ്"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ഡെസ്ക്ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾ നിലവിൽ പരിരക്ഷിച്ചിട്ടില്ല"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ഡെസ്ക്ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ ടാപ്പുചെയ്യുക"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"എല്ലായ്പ്പോഴും ഓണാണ്"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ഓട്ടോമാറ്റിക്"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView നടപ്പാക്കൽ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView നടപ്പാക്കൽ സജ്ജമാക്കുക"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"തിരഞ്ഞെടുത്ത WebView നടപ്പാക്കൽ പ്രവർത്തനരഹിതമാക്കി, ഉപയോഗിക്കുന്നതിന് ഇത് പ്രവർത്തനക്ഷമമാക്കണം, പ്രവർത്തനക്ഷമമാക്കാൻ ആഗ്രഹിക്കുന്നുണ്ടോ?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"വർണ്ണം ക്രമീകരിക്കൽ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ഈ ഫീച്ചർ പരീക്ഷണാത്മകമായതിനാൽ പ്രകടനത്തെ ബാധിച്ചേക്കാം."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ഉപയോഗിച്ച് അസാധുവാക്കി"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"ഏകദേശം <xliff:g id="TIME">%2$s</xliff:g> ശേഷിക്കുന്നു"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ഏകദേശം <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ഏകദേശം <xliff:g id="TIME">%2$s</xliff:g> ശേഷിക്കുന്നു"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - പൂർണ്ണമായും ചാർജ്ജാകുന്നതിന്, <xliff:g id="TIME">%2$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index 3b5d5f1..8bdd880 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Апп-ыг гадаад санах ойд хадгалахыг зөвшөөрөх"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест утгыг нь үл хамааран дурын апп-ыг гадаад санах ойд бичих боломжтой болгодог"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааг олон цонхонд хэмжээг нь өөрчилж болохуйц болгох."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааны хэмжээг олон цонхонд өөрчилж болохуйц болгоно уу."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлдэг."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлнэ үү."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Десктоп нөөшлөлтийн нууц үг"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Десктоп бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Компьютерийн бүтэн нөөцлөлтийн нууц үгийг өөрчлөх, устгах бол дарна уу"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Идэвхгүй"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Байнга асаалттай"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматаар"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView хэрэгжилт"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView хэрэгжилтийг тохируулах"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Сонгосон WebView хэрэгжүүлэлтийг идэвхгүй болгосон бөгөөд хэрэглэхийн тулд заавал идэвхжүүлэх шаардлагатай. Үүнийг идэвхжүүлэх үү?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Өнгө тохируулах"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Энэ функц туршилтынх бөгөөд ажиллагаанд нөлөөлж болзошгүй."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ойролцоогоор <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ойролцоогоор <xliff:g id="TIME">%2$s</xliff:g> үлдсэн"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"дүүртэл <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Дүүрэн"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Админ идэвхгүй болгосон"</string>
<string name="home" msgid="8263346537524314127">"Нүүр"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> өмнө"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> үлдсэн"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index 493f579..92247f5 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"बाह्यवर अॅप्सना अनुमती देण्याची सक्ती करा"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, कोणत्याही अॅपला बाह्य संचयनावर लेखन केले जाण्यासाठी पात्र बनविते"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"क्रियाकलापाचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सक्षम करा"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करते."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करा."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बॅकअप संकेतशब्द"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप पूर्ण बॅक अप सध्या संरक्षित नाहीत"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला संकेतशब्द बदलण्यासाठी किंवा काढण्यासाठी टॅप करा"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"अक्षम केले"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"नेहमी चालू"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"स्वयंचलित"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"वेबदृश्य अंमलबजावणी"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"वेबदृश्य अंमलबजावणी सेट करा"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"निवडलेली WebView अंमलबजावणी अक्षम आहे आणि वापरण्यास सक्षम असणे आवश्यक आहे, आपण ती सक्षम करू इच्छिता?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"रंग सुधारणा"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"हे वैशिष्ट्य प्रायोगिक आहे आणि कदाचित कार्यप्रदर्शन प्रभावित करू शकते."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"अंदाजे. <xliff:g id="TIME">%2$s</xliff:g> शिल्लक"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"अंदाजे. <xliff:g id="TIME">%1$s</xliff:g> शिल्लक"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - अंदाजे. <xliff:g id="TIME">%2$s</xliff:g> शिल्लक"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूर्ण होण्यात"</string>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 0509159..45f5c6f 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Benarkan apl secara paksa pada storan luaran"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Menjadikan sebarang apl layak ditulis ke storan luaran, walau apa juga nilai manifesnya"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktiviti supaya boleh diubah saiz"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Menjadikan semua aktiviti boleh diubah saiz untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Bolehkan semua saiz aktiviti diubah untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Dayakan tetingkap bentuk bebas"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Mendayakan sokongan untuk tetingkap bentuk bebas percubaan."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Dayakan sokongan untuk tetingkap bentuk bebas percubaan."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Kata laluan sandaran komputer meja"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sandaran penuh komputer meja tidak dilindungi pada masa ini"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ketik untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh desktop"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Dilumpuhkan"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sentiasa hidup"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatik"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Pelaksanaan WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Tetapkan pelaksanaan WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Pelaksanaan WebView pilihan telah dilumpuhkan dan mesti didayakan untuk digunakan, adakah anda mahu mendayakannya?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Pembetulan warna"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ciri ini adalah percubaan dan boleh menjejaskan prestasi."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Kira-kira <xliff:g id="TIME">%1$s</xliff:g> lagi"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - kira-kira. <xliff:g id="TIME">%2$s</xliff:g> yang tinggal"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> sehingga penuh"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Penuh"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dilumpuhkan oleh pentadbir"</string>
<string name="home" msgid="8263346537524314127">"Skrin Utama"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> yang lalu"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> lagi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index 9f56479..9d722db 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"အပြင်မှာ အတင်း ခွင့်ပြုရန်"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ပြနေတဲ့ တန်ဖိုး ဘယ်လိုပဲရှိနေနေ၊ ဘယ် appကို မဆို အပြင် သိုလှောင်ခန်းသို့ ရေးသားခွင့် ပေးတယ်"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"လုပ်ဆောင်ချက်များ ဆိုက်ညှိရနိုင်ရန် လုပ်ခိုင်းပါ"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"မန်နီးဖက်စ် တန်ဖိုးမရွေး၊ လုပ်ဆောင်ချက် အားလုံး ဆိုက်ညှိရနိုင်အောင် လုပ်ပေးပါ။"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"မန်နီးဖက်စ်တန်ဖိုးများ မည်မျှပင်ရှိစေကာမူ၊ ဝင်းဒိုးများအတွက် လှုပ်ရှားမှုများအားလုံးကို အရွယ်အစားချိန်ခြင်း ပြုလုပ်ပါ။"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"အခမဲ့ပုံစံ ဝင်းဒိုးကို ဖွင့်ပါ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"စမ်းသပ်မှု အခမဲ့ပုံစံ ဝင်းဒိုးများအတွက် ပံ့ပိုးမှုကို ဖွင့်ပါ။"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ပုံစံမျိုးစုံဝင်းဒိုးများစမ်းသပ်မှုအတွက် အထောက်အပံ့ကိုဖွင့်ပါ"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop အရန်စကားဝှက်"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"အလုပ်ခုံတွင် အရန်သိမ်းဆည်းခြင်းများကို လောလောဆယ် မကာကွယ်နိုင်ပါ။"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"စားပွဲတင်ကွန်ပျူတာကို အပြည့်အဝအရံကူးထားရန်အတွက် စကားဝှက်ကို ပြောင်းရန် သို့မဟုတ် ဖယ်ရှားရန် တို့ပါ။"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"ပိတ်ထား"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"အမြဲတမ်း ဖွင့်ထားရန်"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"အလိုအလျောက်"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView အကောင်အထည်ဖော်မှု"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView အကောင်အထည်ဖော်မှု သတ်မှတ်ပါ"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ရွေးချယ်ထားသည့် WebView လုပ်ဆောင်ခြင်းကို ပိတ်ထားသည်ပြီး အသုံးပြုရန်အတွက် ဖွင့်ရမည်၊ ဖွင့်လိုပါသလား။"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"အရောင်ပြင်ဆင်မှု"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ဒီအင်္ဂါရပ်မှာ စမ်းသပ်မှု ဖြစ်၍ လုပ်ကိုင်မှုကို အကျိုးသက်ရောက်နိုင်သည်။"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ခန့်မှန်းခြေ <xliff:g id="TIME">%1$s</xliff:g> ကျန်ပါသည်"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ခန့်မှန်းခြေ။ <xliff:g id="TIME">%2$s</xliff:g> ကျန်ရှိနေ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> အပြည့်အထိ"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"အပြည့်"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"စီမံခန့်ခွဲသူမှ ပိတ်ထားသည်"</string>
<string name="home" msgid="8263346537524314127">"ပင်မ"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"ပြီးခဲ့သည့် <xliff:g id="ID_1">%1$s</xliff:g> က"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> ကျန်ပါသည်"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 013fe26..ff15482 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Tving frem tillatelse for ekstern lagring av apper"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gjør at apper kan skrives til ekstern lagring, uavhengig av manifestverdier"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til å kunne endre størrelse"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Dette gjør at alle aktivitene kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gjør at alle aktivitetene kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Slå på vinduer i fritt format"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Slår på støtte for vinduer i eksperimentelt fritt format."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Slå på støtte for vinduer i eksperimentelt fritt format."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Passord for sikkerhetskopiering på datamaskin"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Fullstendig sikkerhetskopiering på datamaskin beskyttes ikke for øyeblikket."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Slått av"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Alltid på"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Angi WebView-implementering"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Den valgte implementeringen av nettvisningen er slått av – den må slås på for å brukes. Vil du slå den på?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Fargekorrigering"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Denne funksjonen er eksperimentell og kan påvirke ytelsen."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%1$s</xliff:g> gjenstår"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca. <xliff:g id="TIME">%2$s</xliff:g> igjen"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – fulladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Avslått av administratoren"</string>
<string name="home" msgid="8263346537524314127">"Startside"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> siden"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> gjenstår"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index 715f055..f0cfdab 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"बाह्यमा बल प्रयोगको अनुमति प्राप्त अनुप्रयोगहरू"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"म्यानिफेेस्टको उपेक्षा गरी, कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न योग्य बनाउँछ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"गतिविधिहरू रिसाइज गर्नको लागि बाध्य गर्नुहोस्"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउँछ।"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउँछ।"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"फ्रिफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ्रिफर्म विन्डोहरूका लागि समर्थनलाई सक्रिय गर्छ।"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रयोगात्मक फ्रिफर्म विन्डोहरूका लागि समर्थन सक्रिय गर्नुहोस्।"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटप ब्याकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटप पूर्ण जगेडाहरू हाललाई सुरक्षित छैनन्"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन ट्याप गर्नुहोस्"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"असक्षम गरियो"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"सधैं खुल्ला"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट गर्नुहोस्"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"छनौट गरिएको WebView को कार्यान्वयन असक्षम गरिएको छ र प्रयोग गर्नका लागि सक्रिय गर्नुपर्छ, तपाईँ यसलाई सक्रिय गर्न चाहनुहुन्छ?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"रङ्ग सुधार"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"यो सुविधा प्रयोगात्मक छ र प्रदर्शनमा असर गर्न सक्छ।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"लगभग <xliff:g id="TIME">%2$s</xliff:g> बाँकी छ"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"लगभग <xliff:g id="TIME">%1$s</xliff:g> बाँकी छ"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - लगभग। <xliff:g id="TIME">%2$s</xliff:g> बायाँ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> पूर्ण नभए सम्म"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index bd24201..0dbf5b9 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Toestaan van apps op externe opslag afdwingen"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hierdoor komt een app in aanmerking om te worden geschreven naar externe opslag, ongeacht de manifestwaarden"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Formaat activiteiten geforceerd aanpasbaar maken"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Hiermee wordt het formaat van alle activiteiten aanpasbaar gemaakt, ongeacht de manifestwaarden."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Het formaat van alle activiteiten aanpasbaar maken, ongeacht de manifestwaarden."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Vensters met vrije vorm inschakelen"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Schakelt ondersteuning in voor vensters met experimentele vrije vorm."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ondersteuning voor vensters met experimentele vrije vorm inschakelen."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Wachtwoord desktopback-up"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volledige back-ups naar desktops zijn momenteel niet beveiligd"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tik om het wachtwoord voor volledige back-ups naar desktops te wijzigen of te verwijderen"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Uitgeschakeld"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Altijd aan"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementatie"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-implementatie instellen"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"De gekozen WebView-implementatie is uitgeschakeld en moet worden ingeschakeld voor gebruik. Wil je deze inschakelen?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Kleurcorrectie"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Deze functie is experimenteel en kan invloed hebben op de prestaties."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Overschreven door <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca. <xliff:g id="TIME">%1$s</xliff:g> resterend"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ca. <xliff:g id="TIME">%2$s</xliff:g> resterend"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> tot vol"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Volledig"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Uitgeschakeld door beheerder"</string>
<string name="home" msgid="8263346537524314127">"Startpagina"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> geleden"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> resterend"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index f9c0c11..2f44757 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"ਐਪਸ ਨੂੰ ਬਾਹਰਲੇ ਤੇ ਜ਼ਬਰਦਸਤੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ਇੱਕ ਐਪ ਨੂੰ ਬਾਹਰਲੀ ਸਟੋਰੇਜ ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ, ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ ਤੇ ਵਿਚਾਰ ਕੀਤੇ ਬਿਨਾਂ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ਮੁੜ-ਆਕਾਰ ਬਦਲਣ ਲਈ ਸਰਗਰਮੀਆਂ \'ਤੇ ਜ਼ੋਰ ਦਿਓ"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਮੁੜ-ਆਕਾਰ ਵਿੱਚ ਲਿਆਉਂਦੀ ਹੈ, ਚਾਹੇ ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ਼ ਕੁਝ ਵੀ ਹੋਣ।"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ਮੈਨੀਫੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਆਕਾਰ ਬਦਲਣਯੋਗ ਬਣਾਓ।"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"freeform windows ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ਪ੍ਰਯੋਗਾਤਮਕ freeform windows ਲਈ ਸਮਰਥਨ ਨੂੰ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ।"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ਪ੍ਰਯੋਗਮਈ ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਲਈ ਸਮਰਥਨ ਨੂੰ ਯੋਗ ਬਣਾਓ।"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ਡੈਸਕਟੌਪ ਬੈਕਅਪ ਪਾਸਵਰਡ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ਡੈਸਕਟੌਪ ਪੂਰੇ ਬੈਕਅਪਸ ਇਸ ਵੇਲੇ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਹਨ"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ਡੈਸਕਟਾਪ ਦੇ ਮੁਕੰਮਲ ਬੈਕਅੱਪਾਂ ਲਈ ਪਾਸਵਰਡ ਨੂੰ ਬਦਲਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"ਅਸਮਰੱਥ ਬਣਾਇਆ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ਹਮੇਸ਼ਾ ਚਾਲੂ"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ਆਟੋਮੈਟਿਕ"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ਅਮਲ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ਅਮਲ ਸੈੱਟ ਕਰੋ"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ਚੁਣਿਆ ਗਿਆ WebView ਅਮਲ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ, ਅਤੇ ਵਰਤੋਂ ਕਰਨ ਲਈ ਇਸ ਨੂੰ ਯੋਗ ਬਣਾਇਆ ਜਾਣਾ ਜ਼ਰੂਰੀ ਹੈ, ਕੀ ਤੁਸੀਂ ਇਸ ਨੂੰ ਯੋਗ ਬਣਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"ਰੰਗ ਸੰਸ਼ੋਧਨ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਪ੍ਰਯੋਗਾਤਮਿਕ ਹੈ ਅਤੇ ਪ੍ਰਦਰਸ਼ਨ ਤੇ ਅਸਰ ਪਾ ਸਕਦੀ ਹੈ।"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"ਲਗਭਗ <xliff:g id="TIME">%2$s</xliff:g> ਬਾਕੀ"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"ਲਗਭਗ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਲਗਭਗ <xliff:g id="TIME">%2$s</xliff:g> ਬਾਕੀ"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 4ff0d03..e30925c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Wymuś zezwalanie na aplikacje w pamięci zewn."</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Pozwala na zapis aplikacji w pamięci zewn. niezależnie od wartości w pliku manifestu"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Wymuś zmianę rozmiaru okien aktywności"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Umożliwia zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Zezwól na zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Włącz dowolny rozmiar okien"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Włącza obsługę eksperymentalnej funkcji dowolnego rozmiaru okien."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Włącz obsługę eksperymentalnej funkcji dowolnego rozmiaru okien."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Hasło kopii zapasowej"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Pełne kopie zapasowe na komputerze nie są obecnie chronione"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dotknij, by zmienić lub usunąć hasło pełnych kopii zapasowych na komputerze."</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Wyłączone"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Zawsze włączone"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatycznie"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementacja WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ustaw implementację WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Wybrana implementacja WebView jest wyłączona. Aby jej używać, musisz ją włączyć. Chcesz to zrobić?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcja kolorów"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"To jest funkcja eksperymentalna i może wpływać na działanie urządzenia."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Pozostało około <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostało ok. <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Naładowana"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Wyłączone przez administratora"</string>
<string name="home" msgid="8263346537524314127">"Ekran główny"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> temu"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Pozostało: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index b4251a5..ec54e4f 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forçar permissão de apps em armazenamento externo"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ativar a compatibilidade com janelas de forma livre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desativada"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativada"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação do WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar implementação do WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementação do WebView escolhida está desativada e deve ser ativada para ser usada. Deseja ativá-la?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correção de cor"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Este recurso é experimental e pode afetar o desempenho."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Aproximadamente <xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restantes"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Cheio"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desativada pelo administrador"</string>
<string name="home" msgid="8263346537524314127">"Início"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 3dd9561..ab2a5ae 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forçar perm. de aplicações no armazenamento ext."</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualquer aplic. pode ser gravada no arm. ext., independ. dos valores do manif."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forçar as atividades a serem redimensionáveis"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ativar a compatibilidade com janelas de forma livre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Palavra-passe cópia do comp."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"As cópias de segurança completas no ambiente de trabalho não estão atualmente protegidas"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tocar para alterar ou remover a palavra-passe para cópias de segurança completas no ambiente de trabalho"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desativado"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativado"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Definir implementação WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementação WebView escolhida foi desativada e tem de ser ativada para poder ser utilizada. Pretende ativá-la?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correção da cor"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Esta funcionalidade é experimental e pode afetar o desempenho."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Resta(m) aproximadamente <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Resta(m) aproximadamente <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – resta(m) aprox. <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até ficar completa"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index b4251a5..ec54e4f 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forçar permissão de apps em armazenamento externo"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ativar a compatibilidade com janelas de forma livre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desativada"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativada"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação do WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar implementação do WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"A implementação do WebView escolhida está desativada e deve ser ativada para ser usada. Deseja ativá-la?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Correção de cor"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Este recurso é experimental e pode afetar o desempenho."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Substituído por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Aproximadamente <xliff:g id="TIME">%1$s</xliff:g> restante(s)"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - cerca de <xliff:g id="TIME">%2$s</xliff:g> restantes"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> até concluir"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Cheio"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Desativada pelo administrador"</string>
<string name="home" msgid="8263346537524314127">"Início"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> atrás"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> restante(s)"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index e883d0a..0cfacd7 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -85,7 +85,7 @@
<string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Semnal Wi-Fi: complet."</string>
<string name="process_kernel_label" msgid="3916858646836739323">"Sistem de operare Android"</string>
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicații eliminate"</string>
- <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicaţii și utilizatori eliminaţi"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicații și utilizatori eliminați"</string>
<string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering prin USB"</string>
<string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portabil"</string>
<string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering prin Bluetooth"</string>
@@ -102,7 +102,7 @@
<string name="tts_default_rate_title" msgid="6030550998379310088">"Ritmul vorbirii"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Viteza cu care este vorbit textul"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Limbă"</string>
- <string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizaţi limba sistemului"</string>
+ <string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizați limba sistemului"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Nu ați selectat limba"</string>
<string name="tts_default_lang_summary" msgid="5219362163902707785">"Setează vocea caracteristică limbii pentru textul vorbit"</string>
<string name="tts_play_example_title" msgid="7094780383253097230">"Ascultați un exemplu"</string>
@@ -110,7 +110,7 @@
<string name="tts_install_data_title" msgid="4264378440508149986">"Instalați date vocale"</string>
<string name="tts_install_data_summary" msgid="5742135732511822589">"Instalați datele vocale necesare pentru sintetizarea vorbirii"</string>
<string name="tts_engine_security_warning" msgid="8786238102020223650">"Acest motor de sintetizare a vorbirii poate culege în întregime textul vorbit, inclusiv datele personale cum ar fi parolele și numerele cărților de credit. Metoda provine de la motorul <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Permiteți utilizarea acestui motor de sintetizare a vorbirii?"</string>
- <string name="tts_engine_network_required" msgid="1190837151485314743">"Pentru rezultatul transformării textului în vorbire pentru această limbă este necesară o conexiune de rețea care să funcţioneze."</string>
+ <string name="tts_engine_network_required" msgid="1190837151485314743">"Pentru rezultatul transformării textului în vorbire pentru această limbă este necesară o conexiune de rețea care să funcționeze."</string>
<string name="tts_default_sample_string" msgid="4040835213373086322">"Acesta este un exemplu de sintetizare a vorbirii"</string>
<string name="tts_status_title" msgid="7268566550242584413">"Starea limbii prestabilite"</string>
<string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> este acceptată integral"</string>
@@ -175,7 +175,7 @@
<string name="select_usb_configuration_title" msgid="2649938511506971843">"Selectați configurația USB"</string>
<string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Selectați configurația USB"</string>
<string name="allow_mock_location" msgid="2787962564578664888">"Permiteți locațiile fictive"</string>
- <string name="allow_mock_location_summary" msgid="317615105156345626">"Permiteți locaţiile fictive"</string>
+ <string name="allow_mock_location_summary" msgid="317615105156345626">"Permiteți locațiile fictive"</string>
<string name="debug_view_attributes" msgid="6485448367803310384">"Activați inspectarea atributelor de vizualizare"</string>
<string name="legacy_dhcp_client_summary" msgid="163383566317652040">"Folosiți clientul DHCP din Lollipop în locul noului client Android DHCP."</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Păstrați întotdeauna conexiunea de date mobile activată, chiar și atunci când funcția Wi‑Fi este activată (pentru comutarea rapidă între rețele)."</string>
@@ -183,7 +183,7 @@
<string name="adb_warning_message" msgid="7316799925425402244">"Depanarea USB are exclusiv scopuri de dezvoltare. Utilizați-o pentru a copia date de pe computer pe dispozitiv, pentru a instala aplicații pe dispozitiv fără notificare și pentru a citi datele din jurnale."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Revocați accesul la remedierea erorilor prin USB de pe toate computerele pe care le-ați autorizat anterior?"</string>
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Permiteți setările pentru dezvoltare?"</string>
- <string name="dev_settings_warning_message" msgid="2298337781139097964">"Aceste setări sunt destinate exclusiv utilizării pentru dezvoltare. Din cauza lor, este posibil ca dispozitivul dvs. și aplicațiile de pe acesta să nu mai funcţioneze sau să funcţioneze necorespunzător."</string>
+ <string name="dev_settings_warning_message" msgid="2298337781139097964">"Aceste setări sunt destinate exclusiv utilizării pentru dezvoltare. Din cauza lor, este posibil ca dispozitivul dvs. și aplicațiile de pe acesta să nu mai funcționeze sau să funcționeze necorespunzător."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificați aplicațiile prin USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificați aplicațiile instalate utilizând ADB/ADT, pentru a detecta un comportament dăunător."</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Dezactivează funcția Bluetooth de volum absolut în cazul problemelor de volum apărute la dispozitivele la distanță, cum ar fi volumul mult prea ridicat sau lipsa de control asupra acestuia."</string>
@@ -194,11 +194,11 @@
<string name="debug_debugging_category" msgid="6781250159513471316">"Depanare"</string>
<string name="debug_app" msgid="8349591734751384446">"Selectați aplicația de depanare"</string>
<string name="debug_app_not_set" msgid="718752499586403499">"Nu ați setat o aplicație de depanare"</string>
- <string name="debug_app_set" msgid="2063077997870280017">"Aplicaţie de depanare: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="select_application" msgid="5156029161289091703">"Selectaţi o aplicație"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"Aplicație de depanare: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="select_application" msgid="5156029161289091703">"Selectați o aplicație"</string>
<string name="no_application" msgid="2813387563129153880">"Niciuna"</string>
- <string name="wait_for_debugger" msgid="1202370874528893091">"Aşteptaţi depanatorul"</string>
- <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Înaintea executării, aplicația aşteaptă atașarea depanatorului"</string>
+ <string name="wait_for_debugger" msgid="1202370874528893091">"Așteptați depanatorul"</string>
+ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Înaintea executării, aplicația așteaptă atașarea depanatorului"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Intrare"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Desen"</string>
<string name="debug_hw_drawing_category" msgid="6220174216912308658">"Redare accelerată hardware"</string>
@@ -218,7 +218,7 @@
<string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Straturile hardware clipesc verde la actualizare"</string>
<string name="debug_hw_overdraw" msgid="2968692419951565417">"Depanați suprapunerea"</string>
<string name="disable_overlays" msgid="2074488440505934665">"Dezactivați suprapun. HW"</string>
- <string name="disable_overlays_summary" msgid="3578941133710758592">"Utilizaţi mereu GPU pentru compunerea ecranului"</string>
+ <string name="disable_overlays_summary" msgid="3578941133710758592">"Utilizați mereu GPU pentru compunerea ecranului"</string>
<string name="simulate_color_space" msgid="6745847141353345872">"Simulați spațiu culoare"</string>
<string name="enable_opengl_traces_title" msgid="6790444011053219871">"Monitorizări OpenGL"</string>
<string name="usb_audio_disable_routing" msgid="8114498436003102671">"Dezactivați rutarea audio USB"</string>
@@ -239,7 +239,7 @@
<string name="transition_animation_scale_title" msgid="387527540523595875">"Scară tranziție animații"</string>
<string name="animator_duration_scale_title" msgid="3406722410819934083">"Scară durată Animator"</string>
<string name="overlay_display_devices_title" msgid="5364176287998398539">"Simulați afișaje secundare"</string>
- <string name="debug_applications_category" msgid="4206913653849771549">"Aplicaţii"</string>
+ <string name="debug_applications_category" msgid="4206913653849771549">"Aplicații"</string>
<string name="immediately_destroy_activities" msgid="1579659389568133959">"Nu păstrați activitățile"</string>
<string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Elimină activitățile imediat ce utilizatorul le închide"</string>
<string name="app_process_limit_title" msgid="4280600650253107163">"Limită procese fundal"</string>
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Forțați accesul aplicațiilor la stocarea externă"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Face orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forțați redimensionarea activităților"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Permiteți redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Activați ferestrele cu formă liberă"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activează compatibilitatea pentru ferestrele experimentale cu formă liberă."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Activați compatibilitatea pentru ferestrele experimentale cu formă liberă."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Parolă copie rez. desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"În prezent, copiile de rezervă complete pe desktop nu sunt protejate"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Atingeți ca să modificați sau să eliminați parola pentru backupurile complete pe desktop"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Dezactivată"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Activată permanent"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automat"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementare WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Setați implementarea WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Implementarea WebView aleasă este dezactivată. Pentru a fi folosită, trebuie să fie activată. Doriți să o activați?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Corecția culorii"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Această funcție este experimentală și poate afecta performanțele."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Timp rămas: aproximativ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – timp rămas: aproximativ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> până la încărcare completă"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Complet"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Dezactivată de administrator"</string>
<string name="home" msgid="8263346537524314127">"Ecranul principal"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Acum <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Timp rămas: <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 0f4eaa1..4b3214a 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Разрешить сохранение на внешние накопители"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Разрешает сохранение приложений на внешние накопители независимо от значения манифеста"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Изменение размера в многооконном режиме"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Позволяет менять размер в многооконном режиме (независимо от значений манифеста)"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Разрешить изменение размера в многооконном режиме (независимо от значений манифеста)"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Разрешить создание окон произвольной формы"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Включить экспериментальную функцию создания окон произвольной формы"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Включить экспериментальную функцию создания окон произвольной формы"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Пароль для резервного копирования"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Полные резервные копии в настоящее время не защищены"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Нажмите, чтобы изменить или удалить пароль для резервного копирования"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Отключено"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Всегда включено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматическое переключение"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Сервис WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Настройки сервиса WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Чтобы использовать сервис WebView, включите его. Сделать это?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Коррекция цвета"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Это экспериментальная функция, она может снизить производительность устройства."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Осталось примерно <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – осталось около <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Батарея заряжена"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Отключено администратором"</string>
<string name="home" msgid="8263346537524314127">"Главная"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> назад"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Осталось <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index 6483b18..390e218 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"බාහිර මත යෙදුම් ඉඩ දීම බල කරන්න"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් අභ්යන්තර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ක්රියාකාරකම් ප්රතිප්රමාණ කළ හැකි බවට බල කරන්න"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්රියාකාරකම් බහු-කවුළු සඳහා ප්රතිප්රමාණ කළ හැකි බවට පත් කරයි."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්රියාකාරකම් බහු-කවුළුව සඳහා ප්රතිප්රමාණ කළ හැකි බවට පත් කරන්න."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"අනියම් හැඩැති කවුළු සබල කරන්න"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරයි."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරන්න."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට තට්ටු කරන්න"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"අබලයි"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"සැමවිට ක්රියාත්මක"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ස්වයංක්රීය"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ක්රියාත්මක කිරීම"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ක්රියාත්මක කිරීම සකසන්න"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"තෝරන ලද WebView ක්රියාත්මක කිරීම අබල අතර, භාවිත කිරීමට සබල කළ යුතුය, ඔබ එය සබල කිරීමට අදහස් කරන්නේද?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"වර්ණ නිවැරදි කිරීම"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"මෙම විශේෂාංගය පරීක්ෂණාත්මක සහ ඇතැම් විට ක්රියාකාරිත්වයට බලපෑ හැක."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"දළ වශයෙන් <xliff:g id="TIME">%1$s</xliff:g>ක් ඉතිරිය"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආසන්න <xliff:g id="TIME">%2$s</xliff:g> වම"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> සම්පුර්ණ වන තෙක්"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"පූර්ණ"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"පරිපාලක විසින් අබල කරන ලදී"</string>
<string name="home" msgid="8263346537524314127">"මුල් පිටුව"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>කට පෙර"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g>ක් ඉතිරිය"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index d8e2389..8bf64fa 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Vynútiť povolenie aplikácií na externom úložisku"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Umožňuje zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Vynútiť možnosť zmeny veľkosti aktivít"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veľkosti všetkých aktivít bude možné zmeniť na niekoľko okien (bez ohľadu na hodnoty manifestu)."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Veľkosti všetkých aktivít bude možné zmeniť na niekoľko okien (bez ohľadu na hodnoty manifestu)."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Povoliť okná s voľným tvarom"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Povolenie podpory pre experimentálne okná s voľným tvarom."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Povolenie podpory pre experimentálne okná s voľným tvarom."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pre zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy na počítači nie sú momentálne chránené"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Klepnutím zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Vypnuté"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Vždy zapnuté"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Implementácia komponenta WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavenie implementácie komponenta WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Zvolená implementácia technológie WebView je zakázaná. Ak ju chcete použiť, musíte ju najprv povoliť. Chcete ju povoliť?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Úprava farieb"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Funkcia je experimentálna a môže mať vplyv na výkonnosť."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Prekonané predvoľbou <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Zostáva cca. <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – zostáva približne <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Nabitá"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Zakázané správcom"</string>
<string name="home" msgid="8263346537524314127">"Domov"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"pred <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Zostáva <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index fa0e784..42e589b 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Vsili omogočanje aplikacij v zunanji shrambi"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Vsili povečanje velikosti za aktivnosti"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim povečati velikost za način z več okni."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim povečati velikost za način z več okni."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Omogočanje oken svobodne oblike"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Omogočanje podpore za poskusna okna svobodne oblike"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogočanje podpore za poskusna okna svobodne oblike"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Geslo za varn. kop. rač."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Popolne varnostne kopije namizja trenutno niso zaščitene"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Onemogočeno"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Vedno vklopljeno"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Samodejno"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Izvedba spletnega pogleda"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavitev izvedbe spletnega pogleda"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Izbrana izvedba spletnega pogleda je onemogočena in jo morate omogočiti, če jo želite uporabljati. Ali jo želite omogočiti?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Popravljanje barv"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"To je preskusna funkcija in lahko vpliva na učinkovitost delovanja."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Preglasila nastavitev: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Še približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Še približno <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – še približno <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti"</string>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index f9b62fb..4c77a12 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Detyro lejimin në hapësirën e jashtme"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bën që çdo aplikacion të jetë i përshtatshëm për t\'u shkruar në hapësirën ruajtëse të jashtme, pavarësisht nga vlerat e manifestit"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Detyro madhësinë e ndryshueshme për aktivitetet"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Bën që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Bëj që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktivizo dritaret me formë të lirë"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivizon mbështetjen për dritaret eksperimentale me formë të lirë."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktivizo mbështetjen për dritaret eksperimentale me formë të lirë."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Fjalëkalimi rezervë i kompjuterit"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervimet e plota në kompjuter nuk janë të mbrojtura aktualisht"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Trokit për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Çaktivizuar"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Gjithmonë aktive"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatike"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Zbatimi i WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Cakto zbatimin e WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Është çaktivizuar zbatimi i zgjedhur i WebView dhe duhet të aktivizohet për t\'u përdorur, dëshiron ta aktivizosh?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korrigjimi i ngjyrës"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ky funksion është eksperimental dhe mund të ndikojë në veprimtari."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"Afërsisht <xliff:g id="TIME">%2$s</xliff:g> të mbetura"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Afërsisht <xliff:g id="TIME">%1$s</xliff:g> të mbetura"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - afërsisht <xliff:g id="TIME">%2$s</xliff:g> të mbetura"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të jetë e plotë"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 002e963..8c47025 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Принудно дозволи апликације у спољној"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Принудно омогући промену величине активности"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Омогућава промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Омогући промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Омогући прозоре произвољног формата"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Омогућава подршку за експерименталне прозоре произвољног формата."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Омогућите подршку за експерименталне прозоре произвољног формата."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Лозинка резервне копије за рачунар"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Резервне копије читавог система тренутно нису заштићене"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Онемогућено"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Увек укључено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Аутоматски"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Примена WebView-а"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Подесите примену WebView-а"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Изабрана примена WebView-а је онемогућена, а мора да буде омогућена ради коришћења. Желите ли да је омогућите?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Корекција боја"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ова функција је експериментална и може да утиче на перформансе."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Још отприлике <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – преостало око <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> док се не напуни"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Пуно"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Онемогућио је администратор"</string>
<string name="home" msgid="8263346537524314127">"Почетни"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Пре <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Још <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 9b6f302..d25f9f5 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Tillåt appar i externt lagringsutrymme"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Appen kan skrivas till extern lagring, oavsett manifestvärden"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Framtvinga storleksanpassning för aktiviteter"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Detta gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Aktivera frihandsfönster"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverar stöd för experimentella frihandsfönster."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Aktivera stöd för experimentella frihandsfönster."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Lösenord för säkerhetskopia av datorn"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"De fullständiga säkerhetskopiorna av datorn är för närvarande inte skyddade"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Inaktiverad"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Alltid på"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatiskt"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ange WebView-implementering"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Den valda WebView-implementeringen har inaktiverats och måste aktiveras om du ska kunna använda den. Vill du aktivera den?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Färgkorrigering"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Den här funktionen är experimentell och kan påverka prestandan."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Ca <xliff:g id="TIME">%1$s</xliff:g> kvar"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – ca <xliff:g id="TIME">%2$s</xliff:g> kvar"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> till fulladdat"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Fullt"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Har inaktiverats av administratören"</string>
<string name="home" msgid="8263346537524314127">"Startsida"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"för <xliff:g id="ID_1">%1$s</xliff:g> sedan"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kvar"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index f9171ce..3f1d26a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Lazima uruhusu programu kwenye hifadhi ya nje"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Huweka programu kwenye hifadhi ya nje, bila kujali maelezo"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwa ajili ya dirisha nyingi, bila kujali thamani za faili ya maelezo."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwenye madirisha mengi, bila kuzingatia thamani za faili ya maelezo."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Washa madirisha yenye muundo huru"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Huwasha uwezo wa kutumia madirisha ya majaribio yenye muundo huru."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Ruhusu uwezo wa kutumia madirisha ya majaribio yenye muundo huru."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Nenosiri la hifadhi rudufu ya eneo kazi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Hifadhi rudufu kamili za eneo kazi hazijalindwa kwa sasa"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Gonga ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Imezimwa"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Imewashwa kila wakati"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Otomatiki"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Utekelezaji wa WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Weka utekelezaji wa WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Kipengee ulichochagua cha utekelezaji wa WebView kimezimwa. Ni lazima ukiwashe ili kitumike. Ungependa kukiwasha?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Usahihishaji wa rangi"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Kipengele hiki ni cha majaribio na huenda kikaathiri utendaji."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Imetanguliwa na <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Zimesalia takribani <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia takriban <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - imesalia <xliff:g id="TIME">%2$s</xliff:g> hadi ijae"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Imejaa"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Msimamizi amezima mapendeleo ya mipangilio"</string>
<string name="home" msgid="8263346537524314127">"Mwanzo"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"Zimepita <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Zimesalia <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index 56970a7..f06b0f9 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"பயன்பாடுகளை வெளிப்புறச் சேமிப்பிடத்தில் அனுமதி"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"மேனிஃபெஸ்ட் மதிப்புகளை பொருட்படுத்தாமல், எந்தப் பயன்பாட்டையும் வெளிப்புற சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமைக்கும்."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமை."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"குறிப்பிட்ட வடிவமில்லாத சாளரங்களை இயக்கு"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"பரிசோதனைக்குரிய குறிப்பிட்ட வடிவமில்லாத சாளரங்களுக்கான ஆதரவை இயக்கும்."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"சாளரங்களை அளவுமாற்ற மற்றும் எங்கும் நகர்த்த அனுமதிக்கும் பரிசோதனைக்குரிய அம்சத்திற்கான ஆதரவை இயக்கு."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"டெஸ்க்டாப்பின் முழுக் காப்புப் பிரதிகளுக்கான கடவுச்சொல்லை மாற்ற அல்லது அகற்ற, தட்டவும்"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"முடக்கப்பட்டது"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"எப்போதும் இயக்கத்தில் வை"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"தானியங்கு"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView செயல்படுத்தல்"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView செயல்படுத்தலை அமை"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"தேர்வுசெய்த WebView செயல்படுத்தல் முடக்கப்பட்டுள்ளது, பயன்படுத்த வேண்டுமெனில் அதைக் கண்டிப்பாக இயக்க வேண்டும். இயக்க விரும்புகிறீர்களா?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"வண்ணத்திருத்தம்"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"இது சோதனை முறையிலான அம்சம், இது செயல்திறனைப் பாதிக்கலாம்."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"தோராயமாக <xliff:g id="TIME">%1$s</xliff:g> உள்ளது"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"தோராயம்: <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> உள்ளது"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"முழு சார்ஜிற்கு: <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"முழுமை"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"நிர்வாகி முடக்கியுள்ளார்"</string>
<string name="home" msgid="8263346537524314127">"முகப்பு"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> முன்"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> உள்ளது"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index 5a8c824..e6d594b 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"అనువర్తనాలను బాహ్య నిల్వలో నిర్బంధంగా అనుమతించు"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ఏ అనువర్తనాన్ని అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య నిల్వలో వ్రాయగలిగేలా అనుమతిస్తుంది"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"కార్యాచరణలను పరిమాణం మార్చగలిగేలా నిర్బంధించు"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని కార్యాచరణలను బహుళ విండోల్లో సరిపోయేటట్లు పరిమాణం మార్చగలిగేలా చేస్తుంది."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని కార్యాచరణలను పలు రకాల విండోల్లో సరిపోయేట్లు పరిమాణం మార్చగలిగేలా చేస్తుంది."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"స్వతంత్ర రూప విండోలను ప్రారంభించండి"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ప్రయోగాత్మక స్వతంత్ర రూప విండోలకు మద్దతును ప్రారంభిస్తుంది."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"ప్రయోగాత్మక స్వతంత్ర రూప విండోల కోసం మద్దతును ప్రారంభిస్తుంది."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"డెస్క్టాప్ బ్యాకప్ పాస్వర్డ్"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"డెస్క్టాప్ పూర్తి బ్యాకప్లు ప్రస్తుతం రక్షించబడలేదు"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"డెస్క్టాప్ పూర్తి బ్యాకప్ల కోసం పాస్వర్డ్ను మార్చడానికి లేదా తీసివేయడానికి నొక్కండి"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"నిలిపివేయబడింది"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ఎల్లప్పుడూ ఆన్లో ఉంచు"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"స్వయంచాలకం"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"వెబ్ వీక్షణ అమలు"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"ఎంచుకున్న వెబ్ వీక్షణ అమలు నిలిపివేయబడింది, కానీ ఉపయోగించడానికి తప్పనిసరిగా ప్రారంభించాల్సి ఉంటుంది, మీరు దీన్ని ప్రారంభించాలనుకుంటున్నారా?"</string>
@@ -296,7 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"రంగు సవరణ"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"ఈ లక్షణం ప్రయోగాత్మకమైనది మరియు పనితీరుపై ప్రభావం చూపవచ్చు."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string>
- <string name="power_remaining_duration_only" msgid="4400068916452346544">"సుమారు <xliff:g id="TIME">%2$s</xliff:g> మిగిలి ఉంది"</string>
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"సుమారు <xliff:g id="TIME">%1$s</xliff:g> మిగిలి ఉంది"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - సుమారు <xliff:g id="TIME">%2$s</xliff:g> మిగిలి ఉంది"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - పూర్తిగా నిండటానికి <xliff:g id="TIME">%2$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 5ef3168..ab428a9 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"บังคับให้แอปสามารถใช้ที่เก็บภายนอก"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ให้สามารถเขียนแอปต่างๆ ไปยังที่เก็บภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"บังคับให้กิจกรรมปรับขนาดได้"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"เปิดใช้หน้าต่างรูปแบบอิสระ"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป ไม่ได้รับการป้องกันในขณะนี้"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"แตะเพื่อเปลี่ยนแปลงหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"ปิดใช้แล้ว"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"เปิดใช้เสมอ"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"อัตโนมัติ"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"การใช้งาน WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ตั้งค่าการใช้งาน WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"การใช้งาน WebView ที่เลือกไว้ถูกปิดใช้อยู่ คุณต้องการเปิดใช้เพื่อที่จะใช้งานไหม"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"การแก้สี"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"คุณลักษณะนี้เป็นแบบทดลองและอาจส่งผลต่อประสิทธิภาพการทำงาน"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"แทนที่โดย <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"เหลืออีกประมาณ <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - เหลือประมาณ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> จนกว่าจะเต็ม"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"เต็ม"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"ปิดใช้โดยผู้ดูแลระบบ"</string>
<string name="home" msgid="8263346537524314127">"หน้าแรก"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>ที่ผ่านมา"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"เหลือ <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 8a7d6aa..b21acda 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Pwersahang payagan ang mga app sa external"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mara-write na sa external storage ang anumang app, anuman ang manifest value"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Sapilitang gawing resizable ang mga aktibidad"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gawing resizable para sa multi-window ang lahat ng aktibidad, anuman ang mga manifest value."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Gawing nare-resize ang lahat ng aktibidad para sa multi-window, anuman ang mga value ng manifest."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"I-enable ang mga freeform window"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ine-enable ang suporta para sa mga pang-eksperimentong freeform window."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"I-enable ang suporta para sa mga pang-eksperimentong freeform window."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Password ng pag-backup ng desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kasalukuyang hindi pinoprotektahan ang mga buong pag-backup ng desktop"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"I-tap upang baguhin o alisin ang password para sa mga kumpletong pag-back up sa desktop"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Naka-disable"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Palaging naka-on"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Awtomatiko"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Pagpapatupad sa WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Itakda ang pagpapatupad sa WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Naka-disable ang napiling pagpapatupad sa WebView, at dapat itong i-enable upang magamit, gusto mo ba itong i-enable?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Pagtatama ng kulay"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ang feature na ito ay pinag-eeksperimentuhan at maaaring makaapekto sa pagganap."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Humigit-kumulang <xliff:g id="TIME">%1$s</xliff:g> na lang ang natitira"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - humigit kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> bago mapuno"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Puno"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Na-disable ng administrator"</string>
<string name="home" msgid="8263346537524314127">"Home"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> na ang nakalipas"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> na lang"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 11b975e..beca481 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Harici birimdeki uygulamalara izin vermeye zorla"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bildirilen değerlerden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir hale getirir."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir yap."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Serbest biçimli pencereleri etkinleştir"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Deneysel serbest biçimli pencereleri etkinleştirir."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Deneysel serbest biçimli pencere desteğini etkinleştir."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü yedekleme şifresi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için hafifçe dokunun"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Devre dışı"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Her zaman açık"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Otomatik"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView kullanımı"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView kullanımını ayarla"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Seçilen WebView uygulama şekli devre dışı. Bu uygulama şeklinin kullanılabilmesi için etkinleştirilmesi gerekir. Etkinleştirmek istiyor musunuz?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Renk düzeltme"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu özellik deneyseldir ve performansı etkileyebilir."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Yaklaşık <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - yaklaşık <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - tam şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> var"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Dolu"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Yönetici tarafından devre dışı bırakıldı"</string>
<string name="home" msgid="8263346537524314127">"Ana Ekran"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> önce"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> kaldı"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index ad18d7f..9250dfd 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Примусово записувати додатки в зовнішню пам’ять"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Додатки можна записувати на зовнішню пам’ять незалежно від значень маніфесту"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Примусово масштабувати активність"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Активність масштабуватиметься на кілька вікон, незалежно від значень у файлі маніфесту."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Масштабувати активність на кілька вікон, незалежно від значень у файлі маніфесту."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Увімкнути вікна довільного формату"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Увімкнуться експериментальні вікна довільного формату."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Увімкнути експериментальні вікна довільного формату."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Пароль резерв.копії на ПК"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Повні резервні копії на комп’ютері наразі не захищені"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Торкніться, щоб змінити або видалити пароль для повного резервного копіювання на комп’ютер"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Вимкнено"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Завжди ввімкнено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Застосування WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Налаштувати застосування WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Вибране застосування WebView вимкнено. Увімкнути його?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Корекція кольору"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Це експериментальна функція. Вона може вплинути на продуктивність."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Залишилося приблизно <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – залишилось близько <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного зарядження"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Акумулятор заряджено"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Вимкнено адміністратором"</string>
<string name="home" msgid="8263346537524314127">"Головний екран"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> тому"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Залишилося <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index 670f2e6..3173b33 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"بیرونی پر ایپس کو زبردستی اجازت دیں"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"سرگرمیوں کو ری سائز ایبل بنائیں"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"manifest اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بناتا ہے۔"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"manifest اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بنائیں۔"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"freeform ونڈوز فعال کریں"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"تجرباتی freeform ونڈوز کے لئے سپورٹ فعال کرتا ہے۔"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"تجرباتی freeform ونڈوز کیلئے سپورٹ فعال کریں۔"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے تھپتھپائیں"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"غیر فعال"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ہمیشہ آن"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView کا نفاذ"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView کا نفاذ سیٹ کریں"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"منتخب کردہ WebView کا نفاذ غیر فعال ہے اور استعمال کرنے کیلئے اسے فعال ہونا چاہئیے، کیا آپ اسے فعال کرنا چاہتے ہیں؟"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"رنگ کی اصلاح"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"یہ خصوصیت تجرباتی ہے اور اس کی وجہ سے کاکردگی متاثر ہو سکتی ہے۔"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> کے ذریعہ منسوخ کردیا گیا"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"تقریبا <xliff:g id="TIME">%1$s</xliff:g> باقی ہیں"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - تقریبا <xliff:g id="TIME">%2$s</xliff:g> باقی"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> پورا ہونے تک"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"مکمل"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"منتظم نے غیر فعال کر دیا"</string>
<string name="home" msgid="8263346537524314127">"ہوم"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> قبل"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> باقی ہیں"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index e7dccae..d6d8207 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Tashqi xotira qurilmasidagi ilova dasturlariga majburiy ruxsat berish"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtiradi."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtirish."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Erkin shakldagi oynalarni yoqish"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Tajribaviy erkin shakldagi oynalar ta’minotini yoqadi"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Tajribaviy erkin shakldagi oynalar ta’minotini yoqish."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Zaxira nusxa uchun parol"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Ish stoli to‘liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"O‘chiq"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Har doim yoniq tursin"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ta’minotchisi"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ta’minotchisini sozlash"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Tanlangan WebView ta’minotchisi o‘chirilgan va foydalanish uchun yoqilishi zarur. Yoqilsinmi?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Rangni tuzatish"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Bu funksiya tajribaviy bo‘lib, u qurilma unumdorligiga ta’sir qilishi mumkin."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Taxminan <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> – taxminan <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>, to‘lguncha"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"To‘la"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Administrator tomonidan o‘chirib qo‘yilgan"</string>
<string name="home" msgid="8263346537524314127">"Bosh ekran"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> oldin"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> qoldi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index c803415..5cc34bb 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Buộc cho phép các ứng dụng trên bộ nhớ ngoài"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Giúp ứng dụng bất kỳ đủ điều kiện được ghi vào bộ nhớ ngoài bất kể giá trị tệp kê khai là gì"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Buộc các hoạt động có thể thay đổi kích thước"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Giúp tất cả hoạt động có thể thay đổi kích thước cho nhiều cửa sổ bất kể giá trị tệp kê khai là gì."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Giúp tất cả hoạt động có thể thay đổi kích thước cho nhiều cửa sổ bất kể giá trị tệp kê khai là gì."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Bật cửa sổ dạng tự do"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Bật tính năng hỗ trợ cửa sổ dạng tự do thử nghiệm."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Bật tính năng hỗ trợ cửa sổ dạng tự do thử nghiệm."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Mật khẩu sao lưu của máy tính"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sao lưu toàn bộ máy tính hiện không được bảo vệ"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Nhấn để thay đổi hoặc xóa mật khẩu dành cho sao lưu toàn bộ tới máy tính"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Đã tắt"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Luôn bật"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Tự động"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Triển khai WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Đặt triển khai WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Triển khai WebView đã chọn bị vô hiệu hóa và bạn phải bật để sử dụng tính năng này. Bạn có muốn bật tính năng này không?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Sửa màu"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Tính năng này là tính năng thử nghiệm và có thể ảnh hưởng đến hoạt động."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Còn khoảng <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - còn khoảng <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> cho đến khi đầy"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Đầy"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Bị tắt bởi quản trị viên"</string>
<string name="home" msgid="8263346537524314127">"Màn hình chính"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> trước"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"Còn <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 54a6e7c..4b67322 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -248,9 +248,11 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"强制允许将应用写入外部存储设备"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"强制将活动设为可调整大小"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"将所有活动设为可配合多窗口环境调整大小(无论清单值是什么)。"</string>
+ <!-- no translation found for force_resizable_activities_summary (6667493494706124459) -->
+ <skip />
<string name="enable_freeform_support" msgid="1461893351278940416">"启用可自由调整的窗口"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"启用可自由调整的窗口这一实验性功能。"</string>
+ <!-- no translation found for enable_freeform_support_summary (8247310463288834487) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"桌面备份密码"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌面完整备份当前未设置密码保护"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"点按即可更改或移除用于保护桌面完整备份的密码"</string>
@@ -277,6 +279,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"始终开启"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"自动"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 实现"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"设置 WebView 实现"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"所选的 WebView 实现已停用,您必须先启用 WebView 实现才能加以使用。要启用该 WebView 实现吗?"</string>
@@ -296,8 +302,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"色彩校正"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"此功能为实验性功能,可能会影响性能。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"还剩大约 <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还可用大约<xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需<xliff:g id="TIME">%2$s</xliff:g>充满"</string>
@@ -314,8 +319,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"电量充足"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"已被管理员禁用"</string>
<string name="home" msgid="8263346537524314127">"主屏幕"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"还剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index e95a324..301b90b 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"強制允許應用程式寫入到外部儲存空間"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將所有應用程式寫入到外部儲存完間 (所有資訊清單值)"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"強制可變更活動尺寸"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"在任何資訊清單值下,允許為多個視窗變更所有活動的尺寸。"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"在任何資訊清單值下,允許系統配合多重視窗環境調整所有活動的尺寸。"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形態視窗"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"啟用實驗版自由形態視窗的支援功能。"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"啟用實驗版自由形態視窗的支援功能。"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"桌面電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌上電腦的完整備份目前未受保護"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"輕按即可變更或移除桌上電腦完整備份的密碼"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"永遠開啟"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 設置"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"設定 WebView 設置"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"您選擇的 WebView 設定已停用,您必須先啟用此設定才能加以使用。要啟用此設定嗎?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"色彩校正"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"這是一項實驗性功能,可能會影響效能。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"尚餘大約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 尚餘大約 <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> 後完成充電"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"電量已滿"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"管理員已停用此設定"</string>
<string name="home" msgid="8263346537524314127">"主畫面"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"尚餘 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index bf7ea4e..ce8303c 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"強制允許將應用程式寫入外部儲存空間"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"將活動強制設為可調整大小"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"啟用自由形式視窗"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"啟用實驗版自由形式視窗的支援功能。"</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"啟用實驗版自由形式視窗的支援功能。"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"電腦完整備份目前未受保護"</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"輕按即可變更或移除電腦完整備份的密碼"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"一律開啟"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 實作"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"設定 WebView 實作"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"您所選的 WebView 實作已停用,您必須先啟用 WebView 實作才能加以使用。要啟用該 WebView 實作嗎?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"色彩校正"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"這是一項實驗性功能,可能會對效能造成影響。"</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"還剩大約 <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - 大約還剩 <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"電力充足"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"已由管理員停用"</string>
<string name="home" msgid="8263346537524314127">"主畫面"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"還剩 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index c450f77..149011a 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -248,9 +248,9 @@
<string name="force_allow_on_external" msgid="3215759785081916381">"Phoqelela ukuvumela izinhlelo zokusebenza ngaphandle"</string>
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Yenza noma uluphi uhlelo lokusebenza lifaneleke ukuthi libhalwe kusitoreji sangaphandle, ngaphandle kwamavelu we-manifest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Imisebenzi yamandla izonikezwa usayizi omusha"</string>
- <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Yenza yonke imisebenzi ibe nosayizi abasha kuwindi lokuningi, ngokunganaki amanani we-manifest."</string>
+ <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Yenza yonke imisebenzi ibe nosayizi abasha kumawindi amaningi, ngokunganaki amavelu e-manifest."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"Nika amandla amawindi e-freeform"</string>
- <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Inika amandla usekelo lwamawindi okuhlola e-freeform."</string>
+ <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Nika amandla usekelo lwe-windows yokuhlola kwe-freeform."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Iphasiwedi yokusekela ngokulondoloza ye-Desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Ukusekela ngokulondoloza okugcwele kwe-Desktop akuvikelekile okwamanje."</string>
<string name="local_backup_password_summary_change" msgid="5376206246809190364">"Thepha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
@@ -277,6 +277,10 @@
<string name="night_mode_no" msgid="9171772244775838901">"Kukhutshaziwe"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Njalo ivuliwe"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Okuzenzakalelayo"</string>
+ <!-- no translation found for enable_webview_multiprocess (3405948012467585908) -->
+ <skip />
+ <!-- no translation found for enable_webview_multiprocess_desc (852226124223847283) -->
+ <skip />
<string name="select_webview_provider_title" msgid="4628592979751918907">"Ukufakwa ke-WebView"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Sesba ukufakwa kwe-WebView"</string>
<string name="select_webview_provider_confirmation_text" msgid="6671472080671066972">"Ukusetshenziswa kwe-WebView okukhethiwe kukhutshaziwe, futhi kuzomele kunikwe amandla ukuze kusetshenziswe, ingabe ufisa ukukunika amandla?"</string>
@@ -296,8 +300,7 @@
<string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Ukulungiswa kombala"</string>
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Lesi sici esesilingo futhi singathinta ukusebenza."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"Igitshezwe ngaphezulu yi-<xliff:g id="TITLE">%1$s</xliff:g>"</string>
- <!-- no translation found for power_remaining_duration_only (4400068916452346544) -->
- <skip />
+ <string name="power_remaining_duration_only" msgid="4400068916452346544">"Cishe ngu-<xliff:g id="TIME">%1$s</xliff:g> osele"</string>
<string name="power_discharging_duration" msgid="1605929174734600590">"<xliff:g id="LEVEL">%1$s</xliff:g> - isilinganiso esingu-<xliff:g id="TIME">%2$s</xliff:g> esisele"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="2853265177761520490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> kuze igcwale"</string>
@@ -314,8 +317,6 @@
<string name="battery_info_status_full" msgid="2824614753861462808">"Kugcwele"</string>
<string name="disabled_by_admin_summary_text" msgid="7787027069207263048">"Ikhutshazwe umlawuli"</string>
<string name="home" msgid="8263346537524314127">"Ekhaya"</string>
- <!-- no translation found for charge_length_format (8978516217024434156) -->
- <skip />
- <!-- no translation found for remaining_length_format (7886337596669190587) -->
- <skip />
+ <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> edlule"</string>
+ <string name="remaining_length_format" msgid="7886337596669190587">"<xliff:g id="ID_1">%1$s</xliff:g> osele"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 7012eb2..57c5684 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -684,11 +684,16 @@
<!-- Sound & display settings screen, theme setting value to automatically switch between a light- or dark-colored user interface [CHAR LIMIT=30] -->
<string name="night_mode_auto">Automatic</string>
- <!-- Developer settings: select WebView provider title -->
+ <!-- Developer settings: enable WebView multiprocess name [CHAR LIMIT=30] -->
+ <string name="enable_webview_multiprocess">Enable multiprocess WebView</string>
+ <!-- Developer settings: enable WebView multiprocess summary [CHAR LIMIT=60] -->
+ <string name="enable_webview_multiprocess_desc">Run WebView renderers in an isolated process.</string>
+
+ <!-- Developer settings: select WebView provider title [CHAR LIMIT=30] -->
<string name="select_webview_provider_title">WebView implementation</string>
- <!-- Developer settings: select WebView provider dialog title -->
+ <!-- Developer settings: select WebView provider dialog title [CHAR LIMIT=30] -->
<string name="select_webview_provider_dialog_title">Set WebView implementation</string>
- <!-- Developer settings: confirmation dialog text for the WebView provider selection dialog -->
+ <!-- Developer settings: confirmation dialog text for the WebView provider selection dialog [CHAR LIMIT=NONE] -->
<string name="select_webview_provider_confirmation_text">The chosen WebView implementation is disabled, and must be enabled to be used, do you wish to enable it?</string>
<!-- Developer settings screen, convert userdata to file encryption option name -->
@@ -773,7 +778,7 @@
<string name="battery_info_status_full">Full</string>
<!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->
- <string name="disabled_by_admin_summary_text">Disabled by administrator</string>
+ <string name="disabled_by_admin_summary_text">Controlled by admin</string>
<!-- Option in navigation drawer that leads to Settings main screen [CHAR LIMIT=30] -->
<string name="home">Home</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index c44b638..6d29c5f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -113,6 +113,12 @@
return admin;
}
+ public static boolean hasBaseUserRestriction(Context context,
+ String userRestriction, int userId) {
+ UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ return um.hasBaseUserRestriction(userRestriction, UserHandle.of(userId));
+ }
+
/**
* Checks if keyguard features are disabled by policy.
*
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 9bd4eb1..227b1e8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -70,6 +70,12 @@
}
}
mAttrUserRestriction = data == null ? null : data.toString();
+ // If the system has set the user restriction, then we shouldn't add the padlock.
+ if (RestrictedLockUtils.hasBaseUserRestriction(mContext, mAttrUserRestriction,
+ UserHandle.myUserId())) {
+ mAttrUserRestriction = null;
+ return;
+ }
final TypedValue useAdminDisabledSummary =
attributes.peekValue(R.styleable.RestrictedPreference_useAdminDisabledSummary);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7416fb5..5b865f9 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -40,6 +40,7 @@
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<!-- System tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
@@ -109,6 +110,7 @@
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<application android:label="@string/app_label"
android:forceDeviceEncrypted="true"
diff --git a/packages/SystemUI/res/drawable/ic_colorize.xml b/packages/SystemUI/res/drawable/ic_night_mode.xml
similarity index 95%
rename from packages/SystemUI/res/drawable/ic_colorize.xml
rename to packages/SystemUI/res/drawable/ic_night_mode.xml
index 79fd6d9..caa7a47 100644
--- a/packages/SystemUI/res/drawable/ic_colorize.xml
+++ b/packages/SystemUI/res/drawable/ic_night_mode.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/packages/SystemUI/res/drawable/ic_colorize.xml b/packages/SystemUI/res/drawable/ic_night_mode_disabled.xml
similarity index 91%
copy from packages/SystemUI/res/drawable/ic_colorize.xml
copy to packages/SystemUI/res/drawable/ic_night_mode_disabled.xml
index 79fd6d9..010815a 100644
--- a/packages/SystemUI/res/drawable/ic_colorize.xml
+++ b/packages/SystemUI/res/drawable/ic_night_mode_disabled.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,6 +19,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFFFF"
+ android:fillColor="#4DFFFFFF"
android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-3.12,3.12 -1.93,-1.91 -1.41,1.41 1.42,1.42L3.0,16.25L3.0,21.0l4.75,0.0l8.92,-8.92 1.42,1.42 1.41,-1.41 -1.92,-1.92 3.12,-3.12c0.4,0.0 0.4,-1.0 0.01,-1.42zM6.92,19.0L5.0,17.08l8.06,-8.06 1.92,1.92L6.92,19.0z"/>
</vector>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
index 6f98509..6f153c1 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
@@ -41,26 +41,6 @@
</FrameLayout>
- <FrameLayout
- android:id="@+id/lights_out"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:id="@+id/ends_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" />
-
- <LinearLayout
- android:id="@+id/center_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="horizontal" />
-
- </FrameLayout>
-
<com.android.systemui.statusbar.policy.DeadZone
android:id="@+id/deadzone"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/preference_matrix.xml b/packages/SystemUI/res/layout/calibrate_sliders.xml
similarity index 93%
rename from packages/SystemUI/res/layout/preference_matrix.xml
rename to packages/SystemUI/res/layout/calibrate_sliders.xml
index 1f6066e..0dec8a1 100644
--- a/packages/SystemUI/res/layout/preference_matrix.xml
+++ b/packages/SystemUI/res/layout/calibrate_sliders.xml
@@ -94,11 +94,4 @@
android:layout_weight="1" />
</LinearLayout>
- <Button
- android:id="@+id/apply"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:text="@string/color_apply" />
-
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index 142d13a..2bf4d9c 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -42,26 +42,6 @@
</FrameLayout>
- <FrameLayout
- android:id="@+id/lights_out"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:id="@+id/ends_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" />
-
- <LinearLayout
- android:id="@+id/center_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="horizontal" />
-
- </FrameLayout>
-
<com.android.systemui.statusbar.policy.DeadZone
android:id="@+id/deadzone"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
index 3b7b369..7601efc 100644
--- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
@@ -42,26 +42,6 @@
</FrameLayout>
- <FrameLayout
- android:id="@+id/lights_out"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.android.systemui.statusbar.phone.ReverseLinearLayout
- android:id="@+id/ends_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" />
-
- <com.android.systemui.statusbar.phone.ReverseLinearLayout
- android:id="@+id/center_group_lightsout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="vertical" />
-
- </FrameLayout>
-
<com.android.systemui.statusbar.policy.DeadZone
android:id="@+id/deadzone"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/color_matrix_settings.xml b/packages/SystemUI/res/layout/night_mode_settings.xml
similarity index 100%
rename from packages/SystemUI/res/layout/color_matrix_settings.xml
rename to packages/SystemUI/res/layout/night_mode_settings.xml
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index e550d9c..4d0eb96 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -126,27 +126,6 @@
android:tint="@color/notification_guts_icon_tint" />
</FrameLayout>
-
- <RadioGroup
- android:id="@+id/apply_to"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
- <RadioButton android:id="@+id/apply_to_topic"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- style="@style/TextAppearance.NotificationGuts.Primary"
- android:visibility="gone"
- android:buttonTint="#858383"
- />
- <RadioButton android:id="@+id/apply_to_app"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:text="@string/apply_to_app"
- style="@style/TextAppearance.NotificationGuts.Primary"
- android:visibility="gone"
- android:buttonTint="#858383"
- />
- </RadioGroup>
</LinearLayout>
<!-- buttons -->
<LinearLayout
diff --git a/packages/SystemUI/res/layout/notification_settings_icon_row.xml b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
new file mode 100644
index 0000000..52d07fc
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2016, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.statusbar.NotificationSettingsIconRow
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ >
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/gear_icon"
+ android:layout_width="@dimen/notification_gear_width"
+ android:layout_height="@dimen/notification_gear_height"
+ android:paddingTop="@dimen/notification_gear_top_padding"
+ android:paddingStart="@dimen/notification_gear_padding"
+ android:paddingEnd="@dimen/notification_gear_padding"
+ android:paddingBottom="@dimen/notification_gear_padding"
+ android:src="@drawable/ic_settings"
+ android:tint="@color/notification_gear_color"
+ android:visibility="invisible"
+ android:alpha="0"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ />
+
+</com.android.systemui.statusbar.NotificationSettingsIconRow>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index bed8f1b..858f487 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -50,30 +50,6 @@
android:layout_height="0dp"
android:layout_weight="1" />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingEnd="8dp"
- android:gravity="end">
+ <include layout="@layout/qs_detail_buttons" />
- <TextView
- android:id="@android:id/button2"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:minWidth="132dp"
- android:textAppearance="@style/TextAppearance.QS.DetailButton"
- android:focusable="true" />
-
- <TextView
- android:id="@android:id/button1"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minWidth="88dp"
- android:textAppearance="@style/TextAppearance.QS.DetailButton"
- android:focusable="true"/>
-
- </LinearLayout>
</com.android.systemui.qs.QSDetail>
diff --git a/packages/SystemUI/res/layout/qs_detail_buttons.xml b/packages/SystemUI/res/layout/qs_detail_buttons.xml
new file mode 100644
index 0000000..03ed62b
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_detail_buttons.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingEnd="8dp"
+ android:gravity="end">
+
+ <TextView
+ android:id="@android:id/button2"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:minWidth="132dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton"
+ android:focusable="true" />
+
+ <TextView
+ android:id="@android:id/button1"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="88dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton"
+ android:focusable="true"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_paged_page.xml b/packages/SystemUI/res/layout/qs_paged_page.xml
index eef08ba..a246e0d 100644
--- a/packages/SystemUI/res/layout/qs_paged_page.xml
+++ b/packages/SystemUI/res/layout/qs_paged_page.xml
@@ -19,4 +19,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tile_page"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false" />
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index c23c745..9dd3ad2 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -18,12 +18,14 @@
<com.android.systemui.qs.PagedTileLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false">
<FrameLayout
android:id="@+id/page_decor"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:layout_gravity="bottom">
<com.android.systemui.qs.PageIndicator
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 9f90af2..b8f10db 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -26,7 +26,9 @@
android:layout_marginTop="@dimen/status_bar_header_height"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="8dp" />
+ android:paddingBottom="8dp"
+ android:clipToPadding="false"
+ android:clipChildren="false" />
<include layout="@layout/quick_status_bar_expanded_header" />
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 26152cd..8df2c280 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -32,7 +32,6 @@
>
<LinearLayout
- android:id="@+id/expanded_group"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:gravity="center"
@@ -80,12 +79,12 @@
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
- <ImageView
+ <com.android.systemui.statusbar.phone.ExpandableIndicator
+ android:id="@+id/expand_indicator"
android:layout_width="48dp"
android:layout_height="48dp"
- android:padding="12dp"
- android:src="@drawable/ic_expand_less"
- android:tint="@android:color/white" />
+ android:padding="12dp" />
+
</LinearLayout>
<TextView
@@ -109,6 +108,7 @@
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
+ android:layout_marginTop="4dp"
android:layout_marginStart="16dp"
android:gravity="start"
android:orientation="vertical">
@@ -116,7 +116,6 @@
android:id="@+id/date_time_group"
android:layout_width="wrap_content"
android:layout_height="19dp"
- android:layout_marginTop="4dp"
android:orientation="horizontal">
<include layout="@layout/split_clock_view"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 62fdd42..c4c45bb 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -23,6 +23,14 @@
android:clickable="true"
>
+ <ViewStub
+ android:layout="@layout/notification_settings_icon_row"
+ android:id="@+id/settings_icon_row_stub"
+ android:inflatedId="@+id/notification_settings_icon_row"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ />
+
<com.android.systemui.statusbar.NotificationBackgroundView
android:id="@+id/backgroundNormal"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml b/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml
new file mode 100644
index 0000000..efe63d7
--- /dev/null
+++ b/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- extends LinearLayout -->
+<com.android.systemui.tuner.TunerZenModePanel
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tuner_zen_mode_panel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:visibility="gone"
+ android:orientation="vertical" >
+
+ <View
+ android:id="@+id/zen_embedded_divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginBottom="12dp"
+ android:layout_marginTop="8dp"
+ android:background="@color/qs_tile_divider" />
+
+ <include
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_marginStart="16dp"
+ android:id="@+id/tuner_zen_switch"
+ layout="@layout/qs_detail_header" />
+
+ <include layout="@layout/zen_mode_panel" />
+
+ <include
+ android:id="@+id/tuner_zen_buttons"
+ layout="@layout/qs_detail_buttons" />
+
+</com.android.systemui.tuner.TunerZenModePanel>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 34796cd..e4effd4 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -46,7 +46,7 @@
<include layout="@layout/volume_zen_footer" />
<!-- Only shown from Tuner setting -->
- <include layout="@layout/zen_mode_panel" />
+ <include layout="@layout/tuner_zen_mode_panel" />
</LinearLayout>
</RelativeLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4cd920a..8f69bbb 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -102,6 +102,9 @@
<!-- The color of the circle around the primary user in the user switcher -->
<color name="current_user_border_color">@color/system_accent_color</color>
+ <!-- The color of the gear shown behind a notification -->
+ <color name="notification_gear_color">#ff757575</color>
+
<!-- The "inside" of a notification, reached via longpress -->
<color name="notification_guts_bg_color">#eeeeee</color>
<color name="notification_guts_slider_color">@*android:color/material_deep_teal_500</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index aed5ab2..ee61e00 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -58,7 +58,7 @@
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
<!-- Height of a small notification in the status bar-->
- <dimen name="notification_min_height">84dp</dimen>
+ <dimen name="notification_min_height">86dp</dimen>
<!-- Height of a small notification in the status bar which was used before android N -->
<dimen name="notification_min_height_legacy">64dp</dimen>
@@ -78,6 +78,18 @@
<!-- Minimum layouted height of a notification in the statusbar-->
<dimen name="min_notification_layout_height">48dp</dimen>
+ <!-- Width of the space containing the gear icon behind a notification -->
+ <dimen name="notification_gear_width">64dp</dimen>
+
+ <!-- Height of the space containing the gear icon behind a notification -->
+ <dimen name="notification_gear_height">74dp</dimen>
+
+ <!-- The space above the gear icon displayed behind a notification -->
+ <dimen name="notification_gear_top_padding">30dp</dimen>
+
+ <!-- The space on either side and below the gear icon displayed behind a notification -->
+ <dimen name="notification_gear_padding">20dp</dimen>
+
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">17dip</dimen>
@@ -166,6 +178,7 @@
<dimen name="qs_date_alarm_anim_translation">26dp</dimen>
<dimen name="qs_date_collapsed_text_size">14sp</dimen>
<dimen name="qs_date_text_size">16sp</dimen>
+ <dimen name="qs_header_gear_translation">150dp</dimen>
<dimen name="qs_page_indicator_size">12dp</dimen>
<dimen name="qs_tile_icon_size">24dp</dimen>
<dimen name="qs_tile_text_size">12sp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fa5b1a9..0bd7c4e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -810,12 +810,6 @@
<!-- Interruption level: Alarms only. Optimized for narrow two-line display. [CHAR LIMIT=40] -->
<string name="interruption_level_alarms_twoline">Alarms\nonly</string>
- <!-- Interruption level: All interruptions. [CHAR LIMIT=40] -->
- <string name="interruption_level_all">All</string>
-
- <!-- Interruption level: All interruptions. Optimized for narrow two-line display. [CHAR LIMIT=40] -->
- <string name="interruption_level_all_twoline">All\n</string>
-
<!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
<string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
@@ -1240,29 +1234,43 @@
<!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
<string name="notification_done">Done</string>
- <!-- Label for no color transform [CHAR LIMIT=30] -->
- <string name="color_matrix_none">Normal colors</string>
+ <!-- SysUI Tuner: Color and appearance screen title [CHAR LIMIT=50] -->
+ <string name="color_and_appearance">Color and appearance</string>
- <!-- Label for night color transform [CHAR LIMIT=30] -->
- <string name="color_matrix_night">Night colors</string>
+ <!-- SysUI Tuner: Name of the night mode feature [CHAR LIMIT=30] -->
+ <string name="night_mode">Night mode</string>
- <!-- Label for custom color transform [CHAR LIMIT=30] -->
- <string name="color_matrix_custom">Custom colors</string>
+ <!-- SysUI Tuner: Name of calibrate display dialog [CHAR LIMIT=30] -->
+ <string name="calibrate_display">Calibrate display</string>
- <!-- Label for auto color transforms [CHAR LIMIT=30] -->
- <string name="color_matrix_auto">Auto</string>
+ <!-- SysUI Tuner: Summary of night mode when its on [CHAR LIMIT=NONE] -->
+ <string name="night_mode_on">On</string>
- <!-- Label for unknown color transform [CHAR LIMIT=30] -->
- <string name="color_matrix_unknown">Unknown colors</string>
+ <!-- SysUI Tuner: Summary of night mode when its off [CHAR LIMIT=NONE] -->
+ <string name="night_mode_off">Off</string>
- <!-- Title for color transform [CHAR LIMIT=30] -->
- <string name="color_transform">Color modification</string>
+ <!-- SysUI Tuner: Label for switch to turn on night mode automatically [CHAR LIMIT=50] -->
+ <string name="turn_on_automatically">Turn on automatically</string>
- <!-- Title for setting to show Quick Settings tile [CHAR LIMIT=60] -->
- <string name="color_matrix_show_qs">Show Quick Settings tile</string>
+ <!-- SysUI Tuner: Summary for switch to turn on night mode automatically [CHAR LIMIT=NONE] -->
+ <string name="turn_on_auto_summary">Switch into Night Mode as appropriate for location and time of day</string>
- <!-- Title for switch to enable custom color transform [CHAR LIMIT=60] -->
- <string name="color_enable_custom">Enable custom transform</string>
+ <!-- SysUI Tuner: Label for section controlling what night mode does [CHAR LIMIT=60] -->
+ <string name="when_night_mode_on">When Night Mode is on</string>
+
+ <!-- SysUI Tuner: Switch controlling whether dark theme is turned on with night mode [CHAR LIMIT=45] -->
+ <string name="use_dark_theme">Use dark theme for Android OS</string>
+
+ <!-- SysUI Tuner: Switch controlling whether tint is changed with night mode [CHAR LIMIT=45] -->
+ <string name="adjust_tint">Adjust tint</string>
+
+ <!-- SysUI Tuner: Switch controlling whether brightness is changed with night mode [CHAR LIMIT=45] -->
+ <string name="adjust_brightness">Adjust brightness</string>
+
+ <!-- SysUI Tuner: Disclaimer about using dark theme with night mode [CHAR LIMIT=NONE] -->
+ <string name="night_mode_disclaimer">The dark theme is applied to
+ core areas of Android OS that are normally displayed in a light theme,
+ such as Settings and notifications.</string>
<!-- Button to apply settings [CHAR LIMIT=30] -->
<string name="color_apply">Apply</string>
@@ -1301,15 +1309,14 @@
<string name="keyboard_shortcut_group_system_back">Back</string>
<!-- SysUI Tuner: Option to show full do not disturb panel in volume [CHAR LIMIT=60] -->
- <string name="tuner_full_zen_title">Show do not disturb in volume</string>
- <!-- SysUI Tuner: Summary of option to show full do not disturb panel in volume [CHAR LIMIT=NONE] -->
- <string name="tuner_full_zen_summary">Allow full control of do not disturb in the volume dialog.</string>
+ <string name="tuner_full_zen_title">Show with volume controls</string>
- <!-- SysUI Tuner: Label for screen about volume and do not disturb settings [CHAR LIMIT=60] -->
- <string name="volume_and_do_not_disturb">Volume and Do not disturb</string>
+ <!-- SysUI Tuner: Label for screen about do not disturb settings [CHAR LIMIT=60] -->
+ <string name="volume_and_do_not_disturb">Do not disturb</string>
- <!-- SysUI Tuner: Switch to control volume down behavior [CHAR LIMIT=60] -->
- <string name="volume_down_silent">Enter do not disturb on volume down</string>
+ <!-- SysUI Tuner: Switch to control whether volume buttons enter/exit do
+ not disturb [CHAR LIMIT=60] -->
+ <string name="volume_dnd_silent">Volume buttons shortcut</string>
<!-- SysUI Tuner: Switch to control volume up behavior [CHAR LIMIT=60] -->
<string name="volume_up_silent">Exit do not disturb on volume up</string>
@@ -1329,9 +1336,6 @@
<!-- Accessibility description of headset icon [CHAR LIMIT=NONE] -->
<string name="accessibility_status_bar_headset">Headset connected</string>
- <!-- Explanation of the status bar section of the tuner [CHAR LIMIT=NONE] -->
- <string name="tuner_status_bar_explanation">Enable or disable icons from being shown in the status bar.</string>
-
<!-- Label for quick settings tile for data saver [CHAR LIMIT=30] -->
<string name="data_saver">Data Saver</string>
@@ -1344,6 +1348,9 @@
<!-- Label for feature switch [CHAR LIMIT=30] -->
<string name="switch_bar_on">On</string>
+ <!-- Label for feature switch [CHAR LIMIT=30] -->
+ <string name="switch_bar_off">Off</string>
+
<!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
<string name="nav_bar">Navigation bar</string>
@@ -1404,4 +1411,21 @@
<!-- Button to edit the tile ordering of quick settings [CHAR LIMIT=60] -->
<string name="qs_edit">Edit</string>
+ <!-- SysUI Tuner: Options for how clock is displayed [CHAR LIMIT=NONE] -->
+ <string name="tuner_time">Time</string>
+
+ <!-- SysUI Tuner: Options for how clock is displayed [CHAR LIMIT=NONE] -->
+ <string-array name="clock_options">
+ <item>Show hours, minutes, and seconds</item>
+ <item>Show hours and minutes (default)</item>
+ <item>Don\'t show this icon</item>
+ </string-array>
+
+ <!-- SysUI Tuner: Options for how battery is displayed [CHAR LIMIT=NONE] -->
+ <string-array name="battery_options">
+ <item>Always show percentage</item>
+ <item>Show percentage when charging (default)</item>
+ <item>Don\'t show this icon</item>
+ </string-array>
+
</resources>
diff --git a/packages/SystemUI/res/xml/color_and_appearance.xml b/packages/SystemUI/res/xml/color_and_appearance.xml
new file mode 100644
index 0000000..21f890e
--- /dev/null
+++ b/packages/SystemUI/res/xml/color_and_appearance.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:title="@string/color_and_appearance">
+
+ <Preference
+ android:key="night_mode"
+ android:title="@string/night_mode"
+ android:fragment="com.android.systemui.tuner.NightModeFragment" />
+
+ <com.android.systemui.tuner.CalibratePreference
+ android:key="calibrate"
+ android:title="@string/calibrate_display" />
+
+</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/night_mode.xml b/packages/SystemUI/res/xml/night_mode.xml
new file mode 100644
index 0000000..d5f5333
--- /dev/null
+++ b/packages/SystemUI/res/xml/night_mode.xml
@@ -0,0 +1,47 @@
+<?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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ android:title="@string/night_mode">
+
+ <SwitchPreference
+ android:key="auto"
+ android:title="@string/turn_on_automatically"
+ android:summary="@string/turn_on_auto_summary" />
+
+ <PreferenceCategory
+ android:title="@string/when_night_mode_on">
+
+ <SwitchPreference
+ android:key="dark_theme"
+ android:title="@string/use_dark_theme" />
+
+ <SwitchPreference
+ android:key="adjust_tint"
+ android:title="@string/adjust_tint" />
+
+ <SwitchPreference
+ android:key="adjust_brightness"
+ android:title="@string/adjust_brightness" />
+
+ </PreferenceCategory>
+
+ <Preference
+ android:selectable="false"
+ android:summary="@string/night_mode_disclaimer" />
+
+</PreferenceScreen>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 39281bc..023a3f0 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -18,19 +18,10 @@
xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:title="@string/system_ui_tuner">
- <com.android.systemui.tuner.TunerSwitch
- android:key="qs_show_brightness"
- android:title="@string/show_brightness"
- sysui:defValue="true" />
-
<PreferenceScreen
android:key="status_bar"
android:title="@string/status_bar" >
- <Preference
- android:selectable="false"
- android:summary="@string/tuner_status_bar_explanation" />
-
<com.android.systemui.tuner.StatusBarSwitch
android:key="rotate"
android:title="@string/status_bar_settings_auto_rotation" />
@@ -91,9 +82,10 @@
<!-- other weird signal stuff -->
- <com.android.systemui.tuner.StatusBarSwitch
- android:key="battery"
- android:title="@string/battery" />
+ <com.android.systemui.tuner.BatteryPreference
+ android:title="@string/battery"
+ android:summary="%s"
+ android:entries="@array/battery_options" />
<com.android.systemui.tuner.StatusBarSwitch
android:key="alarm_clock"
@@ -101,12 +93,37 @@
<!-- secure -->
- <com.android.systemui.tuner.StatusBarSwitch
- android:key="clock"
- android:title="@string/clock" />
+ <com.android.systemui.tuner.ClockPreference
+ android:title="@string/tuner_time"
+ android:summary="%s"
+ android:entries="@array/clock_options" />
</PreferenceScreen>
+ <Preference
+ android:key="color_transform"
+ android:title="@string/color_and_appearance"
+ android:fragment="com.android.systemui.tuner.ColorAndAppearanceFragment" />
+
+ <PreferenceScreen
+ android:key="volume_and_do_not_disturb"
+ android:title="@string/volume_and_do_not_disturb">
+
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="sysui_show_full_zen"
+ android:title="@string/tuner_full_zen_title" />
+
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="sysui_volume_down_silent,sysui_volume_up_silent"
+ android:title="@string/volume_dnd_silent"
+ sysui:defValue="true" />
+
+ </PreferenceScreen>
+
+ <Preference
+ android:key="nav_bar"
+ android:title="@string/nav_bar"
+ android:fragment="com.android.systemui.tuner.NavBarTuner" />
<PreferenceScreen
android:key="overview"
@@ -124,53 +141,6 @@
</PreferenceScreen>
- <SwitchPreference
- android:key="battery_pct"
- android:title="@string/show_battery_percentage"
- android:summary="@string/show_battery_percentage_summary"
- android:persistent="false" />
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="clock_seconds"
- android:title="@string/clock_seconds"
- android:summary="@string/clock_seconds_desc" />
-
- <Preference
- android:key="demo_mode"
- android:title="@string/demo_mode"
- android:fragment="com.android.systemui.tuner.DemoModeFragment" />
-
- <Preference
- android:key="color_transform"
- android:title="@string/color_transform"
- android:fragment="com.android.systemui.tuner.ColorMatrixFragment" />
-
- <PreferenceScreen
- android:key="volume_and_do_not_disturb"
- android:title="@string/volume_and_do_not_disturb">
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="sysui_show_full_zen"
- android:title="@string/tuner_full_zen_title"
- android:summary="@string/tuner_full_zen_summary" />
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="sysui_volume_down_silent"
- android:title="@string/volume_down_silent"
- sysui:defValue="true" />
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="sysui_volume_up_silent"
- android:title="@string/volume_up_silent"
- sysui:defValue="true" />
-
- </PreferenceScreen>
-
- <Preference
- android:key="nav_bar"
- android:title="@string/nav_bar"
- android:fragment="com.android.systemui.tuner.NavBarTuner" />
-
<!-- Warning, this goes last. -->
<Preference
android:summary="@string/tuner_persistent_warning"
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 33b43fe..33f3c30 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -69,9 +69,9 @@
private float mPerpendicularInitialTouchPos;
private boolean mDragging;
private View mCurrView;
- private View mCurrAnimView;
private boolean mCanCurrViewBeDimissed;
private float mDensityScale;
+ private float mTranslation = 0;
private boolean mLongPressSent;
private LongPressListener mLongPressListener;
@@ -121,7 +121,7 @@
return mSwipeDirection == X ? ev.getY() : ev.getX();
}
- private float getTranslation(View v) {
+ protected float getTranslation(View v) {
return mSwipeDirection == X ? v.getTranslationX() : v.getTranslationY();
}
@@ -130,7 +130,7 @@
vt.getYVelocity();
}
- private ObjectAnimator createTranslationAnimation(View v, float newPos) {
+ protected ObjectAnimator createTranslationAnimation(View v, float newPos) {
ObjectAnimator anim = ObjectAnimator.ofFloat(v,
mSwipeDirection == X ? View.TRANSLATION_X : View.TRANSLATION_Y, newPos);
return anim;
@@ -141,7 +141,17 @@
vt.getXVelocity();
}
- private void setTranslation(View v, float translate) {
+ protected Animator getViewTranslationAnimator(View v, float target,
+ AnimatorUpdateListener listener) {
+ ObjectAnimator anim = createTranslationAnimation(v, target);
+ anim.addUpdateListener(listener);
+ return anim;
+ }
+
+ protected void setTranslation(View v, float translate) {
+ if (v == null) {
+ return;
+ }
if (mSwipeDirection == X) {
v.setTranslationX(translate);
} else {
@@ -237,15 +247,16 @@
mTouchAboveFalsingThreshold = false;
mDragging = false;
mLongPressSent = false;
- mCurrView = mCallback.getChildAtPosition(ev);
mVelocityTracker.clear();
+ mCurrView = mCallback.getChildAtPosition(ev);
+
if (mCurrView != null) {
- mCurrAnimView = mCallback.getChildContentView(mCurrView);
+ onDownUpdate(mCurrView);
mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView);
mVelocityTracker.addMovement(ev);
mInitialTouchPos = getPos(ev);
mPerpendicularInitialTouchPos = getPerpendicularPos(ev);
-
+ mTranslation = getTranslation(mCurrView);
if (mLongPressListener != null) {
if (mWatchLongPress == null) {
mWatchLongPress = new Runnable() {
@@ -268,7 +279,6 @@
}
mHandler.postDelayed(mWatchLongPress, mLongPressTimeout);
}
-
}
break;
@@ -283,8 +293,8 @@
&& Math.abs(delta) > Math.abs(deltaPerpendicular)) {
mCallback.onBeginDrag(mCurrView);
mDragging = true;
- mInitialTouchPos = getPos(ev) - getTranslation(mCurrAnimView);
-
+ mInitialTouchPos = getPos(ev);
+ mTranslation = getTranslation(mCurrView);
removeLongPressCallback();
}
}
@@ -295,7 +305,6 @@
final boolean captured = (mDragging || mLongPressSent);
mDragging = false;
mCurrView = null;
- mCurrAnimView = null;
mLongPressSent = false;
removeLongPressCallback();
if (captured) return true;
@@ -320,12 +329,11 @@
* @param useAccelerateInterpolator Should an accelerating Interpolator be used
* @param fixedDuration If not 0, this exact duration will be taken
*/
- public void dismissChild(final View view, float velocity, final Runnable endAction,
+ public void dismissChild(final View animView, float velocity, final Runnable endAction,
long delay, boolean useAccelerateInterpolator, long fixedDuration) {
- final View animView = mCallback.getChildContentView(view);
- final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
+ final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
float newPos;
- boolean isLayoutRtl = view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ boolean isLayoutRtl = animView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
if (velocity < 0
|| (velocity == 0 && getTranslation(animView) < 0)
@@ -355,7 +363,13 @@
if (!mDisableHwLayers) {
animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
- ObjectAnimator anim = createTranslationAnimation(animView, newPos);
+ AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
+ }
+ };
+
+ Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
if (useAccelerateInterpolator) {
anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
} else {
@@ -367,8 +381,8 @@
}
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
- updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
- mCallback.onChildDismissed(view);
+ updateSwipeProgressFromOffset(animView, canBeDismissed);
+ mCallback.onChildDismissed(animView);
if (endAction != null) {
endAction.run();
}
@@ -377,11 +391,6 @@
}
}
});
- anim.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
- }
- });
prepareDismissAnimation(animView, anim);
anim.start();
}
@@ -393,21 +402,21 @@
// Do nothing
}
- public void snapChild(final View view, float velocity) {
- final View animView = mCallback.getChildContentView(view);
- final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(animView);
- ObjectAnimator anim = createTranslationAnimation(animView, 0);
+ public void snapChild(final View animView, final float targetLeft, float velocity) {
+ final boolean canBeDismissed = mCallback.canChildBeDismissed(animView);
+ AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed);
+ }
+ };
+
+ Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
int duration = SNAP_ANIM_LEN;
anim.setDuration(duration);
- anim.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
- }
- });
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animator) {
- updateSwipeProgressFromOffset(animView, canAnimViewBeDismissed);
- mCallback.onChildSnappedBack(animView);
+ updateSwipeProgressFromOffset(animView, canBeDismissed);
+ mCallback.onChildSnappedBack(animView, targetLeft);
}
});
prepareSnapBackAnimation(animView, anim);
@@ -421,6 +430,28 @@
// Do nothing
}
+ /**
+ * Called when there's a down event.
+ */
+ public void onDownUpdate(View currView) {
+ // Do nothing
+ }
+
+ /**
+ * Called on a move event.
+ */
+ protected void onMoveUpdate(View view, float totalTranslation, float delta) {
+ // Do nothing
+ }
+
+ /**
+ * Called in {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)} when the current
+ * view is being animated to dismiss or snap.
+ */
+ public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
+ updateSwipeProgressFromOffset(animView, canBeDismissed);
+ }
+
public boolean onTouchEvent(MotionEvent ev) {
if (mLongPressSent) {
return true;
@@ -456,17 +487,18 @@
// don't let items that can't be dismissed be dragged more than
// maxScrollDistance
if (CONSTRAIN_SWIPE && !mCallback.canChildBeDismissed(mCurrView)) {
- float size = getSize(mCurrAnimView);
- float maxScrollDistance = 0.15f * size;
+ float size = getSize(mCurrView);
+ float maxScrollDistance = 0.25f * size;
if (absDelta >= size) {
delta = delta > 0 ? maxScrollDistance : -maxScrollDistance;
} else {
delta = maxScrollDistance * (float) Math.sin((delta/size)*(Math.PI/2));
}
}
- setTranslation(mCurrAnimView, delta);
- updateSwipeProgressFromOffset(mCurrAnimView, mCanCurrViewBeDimissed);
+ setTranslation(mCurrView, mTranslation + delta);
+ updateSwipeProgressFromOffset(mCurrView, mCanCurrViewBeDimissed);
+ onMoveUpdate(mCurrView, mTranslation + delta, delta);
}
break;
case MotionEvent.ACTION_UP:
@@ -478,12 +510,13 @@
float velocity = getVelocity(mVelocityTracker);
float perpendicularVelocity = getPerpendicularVelocity(mVelocityTracker);
+ float translation = getTranslation(mCurrView);
// Decide whether to dismiss the current view
boolean childSwipedFarEnough = DISMISS_IF_SWIPED_FAR_ENOUGH &&
- Math.abs(getTranslation(mCurrAnimView)) > 0.4 * getSize(mCurrAnimView);
+ Math.abs(translation) > 0.4 * getSize(mCurrView);
boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
(Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
- (velocity > 0) == (getTranslation(mCurrAnimView) > 0);
+ (velocity > 0) == (translation > 0);
boolean falsingDetected = mCallback.isAntiFalsingNeeded();
if (mFalsingManager.isClassiferEnabled()) {
@@ -502,7 +535,7 @@
} else {
// snappity
mCallback.onDragCancelled(mCurrView);
- snapChild(mCurrView, velocity);
+ snapChild(mCurrView, 0 /* leftTarget */, velocity);
}
}
break;
@@ -518,8 +551,6 @@
public interface Callback {
View getChildAtPosition(MotionEvent ev);
- View getChildContentView(View v);
-
boolean canChildBeDismissed(View v);
boolean isAntiFalsingNeeded();
@@ -530,7 +561,13 @@
void onDragCancelled(View v);
- void onChildSnappedBack(View animView);
+ /**
+ * Called when the child is snapped to a position.
+ *
+ * @param animView the view that was snapped.
+ * @param targetLeft the left position the view was snapped to.
+ */
+ void onChildSnappedBack(View animView, float targetLeft);
/**
* Updates the swipe progress on a child.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 90d56f7..6029c23 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -758,7 +758,7 @@
mPendingLock = false;
}
}
- doKeyguardLaterLockedForChildProfiles();
+ doKeyguardForChildProfilesLocked();
KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);
}
@@ -781,8 +781,7 @@
long timeout;
- if ((mLockPatternUtils.isSeparateProfileChallengeEnabled(userId))
- || policyTimeout <= 0) {
+ if (policyTimeout <= 0) {
timeout = lockAfterTimeout;
} else {
// From DisplaySettings
@@ -815,23 +814,31 @@
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
+ mDelayedShowingSequence);
- doKeyguardLaterLockedForChildProfiles();
+ doKeyguardLaterForChildProfilesLocked();
}
- private void doKeyguardLaterLockedForChildProfiles() {
+ private void doKeyguardLaterForChildProfilesLocked() {
UserManager um = UserManager.get(mContext);
List<UserInfo> profiles = um.getEnabledProfiles(UserHandle.myUserId());
- if (profiles.size() > 1) {
- for (UserInfo info : profiles) {
- if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
- long userTimeout = getLockTimeout(info.id);
- long userWhen = SystemClock.elapsedRealtime() + userTimeout;
- Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
- lockIntent.putExtra(Intent.EXTRA_USER_ID, info.id);
- PendingIntent lockSender = PendingIntent.getBroadcast(
- mContext, 0, lockIntent, PendingIntent.FLAG_CANCEL_CURRENT);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, userWhen, lockSender);
- }
+ for (UserInfo info : profiles) {
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
+ long userTimeout = getLockTimeout(info.id);
+ long userWhen = SystemClock.elapsedRealtime() + userTimeout;
+ Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
+ lockIntent.putExtra(Intent.EXTRA_USER_ID, info.id);
+ PendingIntent lockSender = PendingIntent.getBroadcast(
+ mContext, 0, lockIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, userWhen, lockSender);
+ }
+ }
+ }
+
+ private void doKeyguardForChildProfilesLocked() {
+ UserManager um = UserManager.get(mContext);
+ List<UserInfo> profiles = um.getEnabledProfiles(UserHandle.myUserId());
+ for (UserInfo info : profiles) {
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
+ lockProfile(info.id);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 8e9857d..0915ee1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -27,6 +27,7 @@
private int mNumPages;
private View mDecorGroup;
+ private PageListener mPageListener;
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -36,10 +37,14 @@
public void onPageSelected(int position) {
if (mPageIndicator == null) return;
mPageIndicator.setLocation(position);
+ if (mPageListener != null) {
+ mPageListener.onPageChanged(position);
+ }
}
@Override
- public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ public void onPageScrolled(int position, float positionOffset,
+ int positionOffsetPixels) {
if (mPageIndicator == null) return;
mPageIndicator.setLocation(position + positionOffset);
}
@@ -80,6 +85,10 @@
}
}
+ public void setPageListener(PageListener listener) {
+ mPageListener = listener;
+ }
+
private void postDistributeTiles() {
removeCallbacks(mDistribute);
post(mDistribute);
@@ -198,4 +207,8 @@
return view == object;
}
};
+
+ public interface PageListener {
+ void onPageChanged(int page);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
new file mode 100644
index 0000000..6479b0c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -0,0 +1,208 @@
+/*
+ * 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.util.Log;
+import android.view.View;
+import android.view.View.OnLayoutChangeListener;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.PathInterpolator;
+import android.widget.TextView;
+import com.android.systemui.Interpolators;
+import com.android.systemui.qs.PagedTileLayout.PageListener;
+import com.android.systemui.qs.QSPanel.QSTileLayout;
+import com.android.systemui.qs.QSTile.Host.Callback;
+import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.qs.TouchAnimator.Listener;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener {
+
+ private static final String TAG = "QSAnimator";
+
+ public static final PathInterpolator TRANSLATION_Y_INTERPOLATOR =
+ new PathInterpolator(.1f, .3f, 1, 1);
+
+ public static final float EXPANDED_TILE_DELAY = .7f;
+
+ private final ArrayList<View> mAllViews = new ArrayList<>();
+ private final QuickQSPanel mQuickQsPanel;
+ private final QSPanel mQsPanel;
+ private final QSContainer mQsContainer;
+
+ private boolean mOnFirstPage = true;
+ private TouchAnimator mFirstPageAnimator;
+ private TouchAnimator mFirstPageDelayedAnimator;
+ private TouchAnimator mTranslationYAnimator;
+ private TouchAnimator mNonfirstPageAnimator;
+
+ public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
+ mQsContainer = container;
+ mQuickQsPanel = quickPanel;
+ mQsPanel = panel;
+ mQuickQsPanel.addOnLayoutChangeListener(this);
+ mQsPanel.addOnLayoutChangeListener(this);
+ QSTileLayout tileLayout = mQsPanel.getTileLayout();
+ if (tileLayout instanceof PagedTileLayout) {
+ ((PagedTileLayout) tileLayout).setPageListener(this);
+ } else {
+ Log.w(TAG, "QS Not using page layout");
+ }
+ }
+
+ public void setHost(QSTileHost qsh) {
+ qsh.addCallback(this);
+ }
+
+ @Override
+ public void onPageChanged(int page) {
+ mOnFirstPage = page == 0;
+ if (!mOnFirstPage) {
+ clearAnimationState();
+ }
+ }
+
+ private void updateAnimators() {
+ TouchAnimator.Builder firstPageBuilder = new Builder();
+ TouchAnimator.Builder translationYBuilder = new Builder();
+ TouchAnimator.Builder firstPageDelayedBuilder = new Builder();
+ Collection<QSTile<?>> tiles = mQsPanel.getHost().getTiles();
+ int count = 0;
+ int[] loc1 = new int[2];
+ int[] loc2 = new int[2];
+ firstPageDelayedBuilder.setStartDelay(EXPANDED_TILE_DELAY);
+ firstPageBuilder.setListener(this);
+ translationYBuilder.setInterpolator(TRANSLATION_Y_INTERPOLATOR);
+ mAllViews.clear();
+ for (QSTile<?> tile : tiles) {
+ QSTileBaseView tileView = mQsPanel.getTileView(tile);
+ final TextView label = ((QSTileView) tileView).getLabel();
+ if (count++ < 5) {
+ // Quick tiles.
+ QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
+ final View tileIcon = tileView.getIcon();
+
+ getRelativePosition(loc1, quickTileView.getIcon(), mQsContainer);
+ getRelativePosition(loc2, tileIcon, mQsContainer);
+ final int xDiff = loc2[0] - loc1[0];
+ final int yDiff = loc2[1] - loc1[1];
+ // Move the quick tile right from its location to the new one.
+ firstPageBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
+ translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
+
+ // Counteract the parent translation on the tile. So we have a static base to
+ // animate off from.
+ firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+
+ // Move the real tile's icon and label from the quick tile position to its final
+ // location.
+ firstPageBuilder.addFloat(tileIcon, "translationX", -xDiff, 0);
+ translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
+ firstPageBuilder.addFloat(label, "translationX", -xDiff, 0);
+ translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
+
+ // Fade in the label as we reach the final position.
+ firstPageDelayedBuilder.addFloat(label, "alpha", 0, 1);
+ mAllViews.add(quickTileView);
+ } else {
+ firstPageDelayedBuilder.addFloat(tileView, "alpha", 0, 1);
+ }
+ mAllViews.add(tileView);
+ mAllViews.add(label);
+ }
+ mFirstPageAnimator = firstPageBuilder.build();
+ mFirstPageDelayedAnimator = firstPageDelayedBuilder.build();
+ mTranslationYAnimator = translationYBuilder.build();
+ mNonfirstPageAnimator = new TouchAnimator.Builder()
+ .addFloat(mQuickQsPanel, "alpha", 1, 0)
+ .setEndDelay(.5f)
+ .build();
+ }
+
+ private void getRelativePosition(int[] loc1, View view, View parent) {
+ loc1[0] = 0 + view.getWidth() / 2;
+ loc1[1] = 0;
+ getRelativePositionInt(loc1, view, parent);
+ }
+
+ private void getRelativePositionInt(int[] loc1, View view, View parent) {
+ if(view == parent || view == null) return;
+ loc1[0] += view.getLeft();
+ loc1[1] += view.getTop();
+ getRelativePositionInt(loc1, (View) view.getParent(), parent);
+ }
+
+ public void setPosition(float position) {
+ if (mFirstPageAnimator == null) return;
+ if (mOnFirstPage) {
+ mQuickQsPanel.setAlpha(1);
+ mFirstPageAnimator.setPosition(position);
+ mFirstPageDelayedAnimator.setPosition(position);
+ mTranslationYAnimator.setPosition(position);
+ } else {
+ mNonfirstPageAnimator.setPosition(position);
+ }
+ }
+
+ @Override
+ public void onAnimationAtStart() {
+
+ }
+
+ @Override
+ public void onAnimationAtEnd() {
+ mQuickQsPanel.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void onAnimationStarted() {
+ mQuickQsPanel.setVisibility(View.VISIBLE);
+ }
+
+ private void clearAnimationState() {
+ final int N = mAllViews.size();
+ mQuickQsPanel.setAlpha(0);
+ for (int i = 0; i < N; i++) {
+ View v = mAllViews.get(i);
+ v.setAlpha(1);
+ v.setTranslationX(1);
+ v.setTranslationY(1);
+ }
+ }
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ updateAnimators();
+ }
+
+ @Override
+ public void onTilesChanged() {
+ // Give the QS panels a moment to generate their new tiles, then create all new animators
+ // hooked up to the new views.
+ mQsPanel.post(mUpdateAnimators);
+ }
+
+ private Runnable mUpdateAnimators = new Runnable() {
+ @Override
+ public void run() {
+ updateAnimators();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index 34dfd6c..c59da8d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -27,6 +27,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
+import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
@@ -49,6 +50,7 @@
private boolean mStackScrollerOverscrolling;
private long mDelay;
+ private QSAnimator mQSAnimator;
public QSContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -61,6 +63,23 @@
mQSDetail = (QSDetail) findViewById(R.id.qs_detail);
mQSDetail.setQsPanel(mQSPanel);
mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
+ mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
+ mQSPanel);
+ }
+
+ public void setHost(QSTileHost qsh) {
+ mQSPanel.setHost(qsh);
+ mHeader.setQSPanel(mQSPanel);
+ mQSDetail.setHost(qsh);
+ mQSAnimator.setHost(qsh);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Since we control our own bottom, be whatever size we want.
+ // Otherwise the QSPanel ends up with 0 height when the window is only the
+ // size of the status bar.
+ super.onMeasure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
}
@Override
@@ -163,6 +182,7 @@
mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
mQSDetail.setFullyExpanded(expansion == 1);
+ mQSAnimator.setPosition(expansion);
updateBottom();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 53abe37..30a9850 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -25,7 +25,6 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
@@ -45,7 +44,7 @@
import java.util.Collection;
/** View that represents the quick settings tile panel. **/
-public class QSPanel extends FrameLayout implements Tunable {
+public class QSPanel extends LinearLayout implements Tunable {
public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
@@ -66,7 +65,6 @@
protected QSFooter mFooter;
private boolean mGridContentVisible = true;
- protected LinearLayout mQsContainer;
protected QSTileLayout mTileLayout;
private QSCustomizer mCustomizePanel;
@@ -80,20 +78,15 @@
super(context, attrs);
mContext = context;
-
- mQsContainer = new LinearLayout(mContext);
- mQsContainer.setOrientation(LinearLayout.VERTICAL);
- mQsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT));
- addView(mQsContainer);
+ setOrientation(VERTICAL);
mBrightnessView = LayoutInflater.from(context).inflate(
R.layout.quick_settings_brightness_dialog, this, false);
- mQsContainer.addView(mBrightnessView);
+ addView(mBrightnessView);
mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
- R.layout.qs_paged_tile_layout, mQsContainer, false);
- mQsContainer.addView((View) mTileLayout);
+ R.layout.qs_paged_tile_layout, this, false);
+ addView((View) mTileLayout);
findViewById(android.R.id.edit).setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
@@ -107,7 +100,7 @@
});
mFooter = new QSFooter(this, context);
- mQsContainer.addView(mFooter.getView());
+ addView(mFooter.getView());
updateResources();
@@ -187,7 +180,7 @@
final Resources res = mContext.getResources();
mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
mBrightnessPaddingTop = res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top);
- mQsContainer.setPadding(0, mBrightnessPaddingTop, 0, mPanelPaddingBottom);
+ setPadding(0, mBrightnessPaddingTop, 0, mPanelPaddingBottom);
for (TileRecord r : mRecords) {
r.tile.clearState();
}
@@ -214,6 +207,9 @@
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
+ if (!mExpanded && mTileLayout instanceof PagedTileLayout) {
+ ((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
+ }
MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, mExpanded);
if (!mExpanded) {
closeDetail();
@@ -329,7 +325,8 @@
final View.OnLongClickListener longClick = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
- return false;
+ r.tile.longClick();
+ return true;
}
};
r.tileView.init(click, longClick);
@@ -376,7 +373,7 @@
}
public int getGridHeight() {
- return mQsContainer.getMeasuredHeight();
+ return getMeasuredHeight();
}
protected void handleShowDetail(Record r, boolean show) {
@@ -425,7 +422,7 @@
void setGridContentVisibility(boolean visible) {
int newVis = visible ? VISIBLE : INVISIBLE;
- mQsContainer.setVisibility(newVis);
+ setVisibility(newVis);
if (mGridContentVisible != visible) {
MetricsLogger.visibility(mContext, MetricsEvent.QS_PANEL, newVis);
}
@@ -468,6 +465,19 @@
}
}
+ QSTileLayout getTileLayout() {
+ return mTileLayout;
+ }
+
+ QSTileBaseView getTileView(QSTile<?> tile) {
+ for (TileRecord r : mRecords) {
+ if (r.tile == tile) {
+ return r.tileView;
+ }
+ }
+ return null;
+ }
+
private class H extends Handler {
private static final int SHOW_DETAIL = 1;
private static final int SET_TILE_VISIBILITY = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index e363b76..f02424b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -36,7 +36,7 @@
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.DisplayController;
+import com.android.systemui.statusbar.policy.NightModeController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -212,9 +212,11 @@
}
protected void handleLongClick() {
- // optional
+ mHost.startActivityDismissingKeyguard(getLongClickIntent());
}
+ public abstract Intent getLongClickIntent();
+
protected void handleClearState() {
mTmpState = newTileState();
mState = newTileState();
@@ -279,10 +281,11 @@
mCallbacks.clear();
}
- protected void checkIfRestrictionEnforced(State state, String userRestriction) {
+ protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
userRestriction, ActivityManager.getCurrentUser());
- if (admin != null) {
+ if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
+ userRestriction, ActivityManager.getCurrentUser())) {
state.disabledByPolicy = true;
state.enforcedAdmin = admin;
} else {
@@ -400,7 +403,7 @@
UserInfoController getUserInfoController();
BatteryController getBatteryController();
TileServices getTileServices();
- DisplayController getDisplayController();
+ NightModeController getNightModeController();
void removeTile(String tileSpec);
ManagedProfileController getManagedProfileController();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index 1a854c2..f35aacf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -49,6 +49,8 @@
// Default to Quick Tile padding, and QSTileView will specify its own padding.
int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
setPadding(padding, padding, padding, padding);
+ setClipChildren(false);
+ setClipToPadding(false);
}
private Drawable newTileBackground() {
@@ -77,6 +79,7 @@
public void init(OnClickListener click, OnLongClickListener longClick) {
setClickable(true);
setOnClickListener(click);
+ setOnLongClickListener(longClick);
}
@Override
@@ -110,6 +113,10 @@
setContentDescription(state.contentDescription);
}
+ View getIcon() {
+ return mIcon;
+ }
+
private class H extends Handler {
private static final int STATE_CHANGED = 1;
public H() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 0d5d115..98a1c23 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -28,6 +28,7 @@
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import libcore.util.Objects;
/** View that represents a standard quick settings tile. **/
public class QSTileView extends QSTileBaseView {
@@ -57,6 +58,10 @@
setGravity(Gravity.CENTER);
}
+ TextView getLabel() {
+ return mLabel;
+ }
+
private void updateTopPadding() {
Resources res = getResources();
int padding = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top);
@@ -84,14 +89,11 @@
addView(view);
}
- public void init(OnClickListener clickPrimary, OnLongClickListener longClick) {
- setOnClickListener(clickPrimary);
- setOnLongClickListener(longClick);
- }
-
protected void handleStateChanged(QSTile.State state) {
super.handleStateChanged(state);
- mLabel.setText(state.label);
+ if (!Objects.equal(mLabel.getText(), state.label)) {
+ mLabel.setText(state.label);
+ }
mLabel.setEnabled(!state.disabledByPolicy);
mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f208470..abe4c77 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -17,12 +17,10 @@
package com.android.systemui.qs;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Space;
import com.android.systemui.R;
@@ -45,10 +43,10 @@
for (int i = 0; i < mRecords.size(); i++) {
mTileLayout.removeTile(mRecords.get(i));
}
- mQsContainer.removeView((View) mTileLayout);
+ removeView((View) mTileLayout);
}
mTileLayout = new HeaderTileLayout(context);
- mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */);
+ addView((View) mTileLayout, 1 /* Between brightness and footer */);
}
@Override
@@ -103,7 +101,7 @@
private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
- private final ImageView mDownArrow;
+ private final Space mEndSpacer;
public HeaderTileLayout(Context context) {
super(context);
@@ -112,16 +110,10 @@
setGravity(Gravity.CENTER_VERTICAL);
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- int padding =
- mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
- mDownArrow = new ImageView(context);
- mDownArrow.setImageResource(R.drawable.ic_expand_more);
- mDownArrow.setImageTintList(ColorStateList.valueOf(context.getResources().getColor(
- android.R.color.white, null)));
- mDownArrow.setLayoutParams(generateLayoutParams());
- mDownArrow.setPadding(padding, padding, padding, padding);
+ mEndSpacer = new Space(context);
+ mEndSpacer.setLayoutParams(generateLayoutParams());
updateDownArrowMargin();
- addView(mDownArrow);
+ addView(mEndSpacer);
setOrientation(LinearLayout.HORIZONTAL);
}
@@ -132,10 +124,10 @@
}
private void updateDownArrowMargin() {
- LayoutParams params = (LayoutParams) mDownArrow.getLayoutParams();
+ LayoutParams params = (LayoutParams) mEndSpacer.getLayoutParams();
params.setMarginStart(mContext.getResources().getDimensionPixelSize(
R.dimen.qs_expand_margin));
- mDownArrow.setLayoutParams(params);
+ mEndSpacer.setLayoutParams(params);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index f7e2338..55eda98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -81,7 +81,7 @@
record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
previousView = record.tileView.updateAccessibilityOrder(previousView);
}
- setMeasuredDimension(width, (mCellHeight + mCellMargin) * rows + mCellMargin);
+ setMeasuredDimension(width, (mCellHeight + mCellMargin) * rows);
}
private static int exactly(int size) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
new file mode 100644
index 0000000..b33d31d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -0,0 +1,252 @@
+/*
+ * 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.animation.Keyframe;
+import android.util.Log;
+import android.util.MathUtils;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class, that handles similar properties as animators (delay, interpolators)
+ * but can have a float input as to the amount they should be in effect. This allows
+ * easier animation that tracks input.
+ *
+ * All "delays" and "times" are as fractions from 0-1.
+ */
+public class TouchAnimator {
+
+ private final Object[] mTargets;
+ private final Property[] mProperties;
+ private final KeyframeSet[] mKeyframeSets;
+ private final float mStartDelay;
+ private final float mEndDelay;
+ private final float mSpan;
+ private final Interpolator mInterpolator;
+ private final Listener mListener;
+ private float mLastT;
+
+ private TouchAnimator(Object[] targets, Property[] properties, KeyframeSet[] keyframeSets,
+ float startDelay, float endDelay, Interpolator interpolator, Listener listener) {
+ mTargets = targets;
+ mProperties = properties;
+ mKeyframeSets = keyframeSets;
+ mStartDelay = startDelay;
+ mEndDelay = endDelay;
+ mSpan = (1 - mEndDelay - mStartDelay);
+ mInterpolator = interpolator;
+ mListener = listener;
+ }
+
+ public void setPosition(float fraction) {
+ float t = MathUtils.constrain((fraction - mStartDelay) / mSpan, 0, 1);
+ if (mInterpolator != null) {
+ t = mInterpolator.getInterpolation(t);
+ }
+ if (mListener != null) {
+ if (mLastT == 0 || mLastT == 1) {
+ if (t != 0) {
+ mListener.onAnimationStarted();
+ }
+ } else if (t == 1) {
+ mListener.onAnimationAtEnd();
+ } else if (t == 0) {
+ mListener.onAnimationAtStart();
+ }
+ mLastT = t;
+ }
+ for (int i = 0; i < mTargets.length; i++) {
+ Object value = mKeyframeSets[i].getValue(t);
+ mProperties[i].set(mTargets[i], value);
+ }
+ }
+
+ public static class ListenerAdapter implements Listener {
+ @Override
+ public void onAnimationAtStart() { }
+
+ @Override
+ public void onAnimationAtEnd() { }
+
+ @Override
+ public void onAnimationStarted() { }
+ }
+
+ public interface Listener {
+ /**
+ * Called when the animator moves into a position of "0". Start and end delays are
+ * taken into account, so this position may cover a range of fractional inputs.
+ */
+ void onAnimationAtStart();
+
+ /**
+ * Called when the animator moves into a position of "0". Start and end delays are
+ * taken into account, so this position may cover a range of fractional inputs.
+ */
+ void onAnimationAtEnd();
+
+ /**
+ * Called when the animator moves out of the start or end position and is in a transient
+ * state.
+ */
+ void onAnimationStarted();
+ }
+
+ public static class Builder {
+ private List<Object> mTargets = new ArrayList<>();
+ private List<Property> mProperties = new ArrayList<>();
+ private List<KeyframeSet> mValues = new ArrayList<>();
+
+ private float mStartDelay;
+ private float mEndDelay;
+ private Interpolator mInterpolator;
+ private Listener mListener;
+
+ public Builder addFloat(Object target, String property, float... values) {
+ add(target, property, KeyframeSet.ofFloat(values));
+ return this;
+ }
+
+ public Builder addInt(Object target, String property, int... values) {
+ add(target, property, KeyframeSet.ofInt(values));
+ return this;
+ }
+
+ private void add(Object target, String property, KeyframeSet keyframeSet) {
+ mTargets.add(target);
+ mProperties.add(getProperty(target, property));
+ mValues.add(keyframeSet);
+ }
+
+ private static Property getProperty(Object target, String property) {
+ if (target instanceof View) {
+ switch (property) {
+ case "translationX":
+ return View.TRANSLATION_X;
+ case "translationY":
+ return View.TRANSLATION_Y;
+ case "translationZ":
+ return View.TRANSLATION_Z;
+ case "alpha":
+ return View.ALPHA;
+ case "rotation":
+ return View.ROTATION;
+ case "x":
+ return View.X;
+ case "y":
+ return View.Y;
+ case "scaleX":
+ return View.SCALE_X;
+ case "scaleY":
+ return View.SCALE_Y;
+ }
+ }
+ return Property.of(target.getClass(), float.class, property);
+ }
+
+ public Builder setStartDelay(float startDelay) {
+ mStartDelay = startDelay;
+ return this;
+ }
+
+ public Builder setEndDelay(float endDelay) {
+ mEndDelay = endDelay;
+ return this;
+ }
+
+ public Builder setInterpolator(Interpolator intepolator) {
+ mInterpolator = intepolator;
+ return this;
+ }
+
+ public Builder setListener(Listener listener) {
+ mListener = listener;
+ return this;
+ }
+
+ public TouchAnimator build() {
+ return new TouchAnimator(mTargets.toArray(new Object[mTargets.size()]),
+ mProperties.toArray(new Property[mProperties.size()]),
+ mValues.toArray(new KeyframeSet[mValues.size()]),
+ mStartDelay, mEndDelay, mInterpolator, mListener);
+ }
+ }
+
+ private static abstract class KeyframeSet {
+
+ private final float mFrameWidth;
+ private final int mSize;
+
+ public KeyframeSet(int size) {
+ mSize = size;
+ mFrameWidth = 1 / (float) (size - 1);
+ }
+
+ Object getValue(float fraction) {
+ int i;
+ for (i = 1; i < mSize - 1 && fraction > mFrameWidth; i++);
+ float amount = fraction / mFrameWidth;
+ return interpolate(i, amount);
+ }
+
+ protected abstract Object interpolate(int index, float amount);
+
+ public static KeyframeSet ofInt(int... values) {
+ return new IntKeyframeSet(values);
+ }
+
+ public static KeyframeSet ofFloat(float... values) {
+ return new FloatKeyframeSet(values);
+ }
+ }
+
+ private static class FloatKeyframeSet extends KeyframeSet {
+ private final float[] mValues;
+
+ public FloatKeyframeSet(float[] values) {
+ super(values.length);
+ mValues = values;
+ }
+
+ @Override
+ protected Object interpolate(int index, float amount) {
+ float firstFloat = mValues[index - 1];
+ float secondFloat = mValues[index];
+ return firstFloat + (secondFloat - firstFloat) * amount;
+ }
+ }
+
+ private static class IntKeyframeSet extends KeyframeSet {
+
+ private final int[] mValues;
+
+ public IntKeyframeSet(int[] values) {
+ super(values.length);
+ mValues = values;
+ }
+
+ @Override
+ protected Object interpolate(int index, float amount) {
+ int firstFloat = mValues[index - 1];
+ int secondFloat = mValues[index];
+ return (int) (firstFloat + (secondFloat - firstFloat) * amount);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 5c34ceb..45f2d75 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -53,9 +53,9 @@
}
private void addSystemTiles(QSTileHost host) {
- boolean hasColorMod = host.getDisplayController().isEnabled();
+ boolean hasColorMod = host.getNightModeController().isEnabled();
String possible = mContext.getString(R.string.quick_settings_tiles_default)
- + ",hotspot,inversion,saver,work,cast" + (hasColorMod ? ",colors" : "");
+ + ",hotspot,inversion,saver,work,cast" + (hasColorMod ? ",night" : "");
String[] possibleTiles = possible.split(",");
final Handler qsHandler = new Handler(host.getLooper());
final Handler mainHandler = new Handler(Looper.getMainLooper());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 3cd9e67..0709992 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -15,13 +15,18 @@
*/
package com.android.systemui.qs.external;
+import android.app.ActivityManager;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.provider.Settings;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
@@ -156,8 +161,22 @@
}
@Override
- protected void handleUserSwitch(int newUserId) {
- super.handleUserSwitch(newUserId);
+ public Intent getLongClickIntent() {
+ Intent i = new Intent(TileService.ACTION_QS_TILE_PREFERENCES);
+ i.setPackage(mComponent.getPackageName());
+ i = resolveIntent(i);
+ if (i != null) {
+ return i;
+ }
+ return new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(
+ Uri.fromParts("package", mComponent.getPackageName(), null));
+ }
+
+ private Intent resolveIntent(Intent i) {
+ ResolveInfo result = mContext.getPackageManager().resolveActivityAsUser(i, 0,
+ ActivityManager.getCurrentUser());
+ return result != null ? new Intent(TileService.ACTION_QS_TILE_PREFERENCES)
+ .setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
}
@Override
@@ -184,10 +203,6 @@
}
@Override
- protected void handleLongClick() {
- }
-
- @Override
protected void handleUpdateState(State state, Object arg) {
Drawable drawable = mTile.getIcon().loadDrawable(mContext);
int color = mContext.getColor(getColor(mTile.getState()));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 5222e61..f0860fe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
+import android.provider.Settings;
import android.provider.Settings.Global;
import com.android.internal.logging.MetricsLogger;
@@ -68,6 +69,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS);
+ }
+
+ @Override
protected void handleUpdateState(BooleanState state, Object arg) {
final int value = arg instanceof Integer ? (Integer)arg : mSetting.getValue();
final boolean airplaneMode = value != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index 6a9d826..93e075d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -19,6 +19,7 @@
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.provider.Settings;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
@@ -91,6 +92,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+ }
+
+ @Override
protected void handleClick() {
showDetail(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index c4b7944..80f667c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -78,6 +78,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
if (!mController.canConfigBluetooth()) {
mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 15e082a..e0ad002 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -86,6 +86,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_CAST_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
mHost.startRunnableDismissingKeyguard(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 15617c7f..5f87741 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -37,7 +37,7 @@
/** Quick settings tile: Cellular **/
public class CellularTile extends QSTile<QSTile.SignalState> {
- private static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
+ static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
"com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
private final NetworkController mController;
@@ -78,6 +78,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return CELLULAR_SETTINGS;
+ }
+
+ @Override
protected void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory());
if (mDataController.isMobileDataSupported()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index e98734c..42ce69c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
+import android.provider.Settings;
import android.provider.Settings.Secure;
import com.android.internal.logging.MetricsLogger;
@@ -70,6 +72,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mSetting.setValue(mState.value ? 0 : 1);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index c6a98b4..a1789a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -14,6 +14,7 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -44,6 +45,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return CellularTile.CELLULAR_SETTINGS;
+ }
+
+ @Override
protected void handleClick() {
mState.value = !mDataSaverController.isDataSaverEnabled();
mDataSaverController.setDataSaverEnabled(mState.value);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 29ca06b..8982b3e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -29,11 +29,13 @@
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
+import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.Prefs;
import com.android.systemui.R;
+import com.android.systemui.SysUIToast;
import com.android.systemui.qs.QSTile;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.volume.ZenModePanel;
@@ -99,7 +101,20 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return ZEN_SETTINGS;
+ }
+
+ @Override
public void handleClick() {
+ if (mController.isVolumeRestricted()) {
+ // Collapse the panels, so the user can see the toast.
+ mHost.collapsePanels();
+ SysUIToast.makeText(mContext, mContext.getString(
+ com.android.internal.R.string.error_message_change_not_allowed),
+ Toast.LENGTH_LONG).show();
+ return;
+ }
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
if (mState.value) {
mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
@@ -116,8 +131,7 @@
final boolean newValue = zen != Global.ZEN_MODE_OFF;
final boolean valueChanged = state.value != newValue;
state.value = newValue;
- state.disabledByPolicy = mController.isVolumeRestricted();
- checkIfRestrictionEnforced(state, UserManager.DISALLOW_ADJUST_VOLUME);
+ checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index f06634e..c10843a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -18,6 +18,8 @@
import android.app.ActivityManager;
+import android.content.Intent;
+import android.provider.MediaStore;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -60,6 +62,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ }
+
+ @Override
protected void handleClick() {
if (ActivityManager.isUserAMonkey()) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 943b502..ad1c7a0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -16,8 +16,10 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
import android.os.UserManager;
+import android.provider.Settings;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -58,6 +60,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
final boolean isEnabled = (Boolean) mState.value;
MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
@@ -68,8 +75,7 @@
protected void handleUpdateState(BooleanState state, Object arg) {
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
- state.disabledByPolicy = mController.isTetheringAllowed();
- checkIfRestrictionEnforced(state, UserManager.DISALLOW_CONFIG_TETHERING);
+ checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING);
if (arg instanceof Boolean) {
state.value = (boolean) arg;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index bdf95d8..bb5ff8e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -92,6 +92,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return null;
+ }
+
+ @Override
protected void handleLongClick() {
sendIntent("long-click", mOnLongClick, mOnLongClickUri);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 9f41f9a..6533252 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,8 +16,10 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
import android.os.UserManager;
+import android.provider.Settings;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -61,6 +63,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
if (mKeyguard.isSecure() && mKeyguard.isShowing()) {
mHost.startRunnableDismissingKeyguard(new Runnable() {
@@ -87,8 +94,7 @@
// bug is fixed, this should be reverted to only hiding it on secure lock screens:
// state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
state.value = locationEnabled;
- state.disabledByPolicy = mController.isUserLocationRestricted();
- checkIfRestrictionEnforced(state, UserManager.DISALLOW_SHARE_LOCATION);
+ checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_SHARE_LOCATION);
if (locationEnabled) {
state.icon = mEnable;
state.label = mContext.getString(R.string.quick_settings_location_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index c94cf5a..b267ccd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -17,8 +17,10 @@
package com.android.systemui.qs.tiles;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
+import android.provider.Settings;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -60,6 +62,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_DISPLAY_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
if (mController == null) return;
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index ba7ea4d..f1066c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -16,7 +16,9 @@
package com.android.systemui.qs.tiles;
import android.content.Context;
+import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.provider.Settings;
import android.util.Pair;
import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -42,6 +44,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_USER_SETTINGS);
+ }
+
+ @Override
protected void handleClick() {
showDetail(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 7a58f15..7ee795f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -93,6 +93,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return WIFI_SETTINGS;
+ }
+
+ @Override
protected void handleSecondaryClick() {
// Secondary clicks are header clicks, just toggle.
mState.copyTo(mStateBeforeClick);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 053a98a..003e9c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import android.content.Intent;
+import android.provider.Settings;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -52,6 +54,11 @@
}
@Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_SYNC_SETTINGS);
+ }
+
+ @Override
public void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mProfileController.setWorkModeEnabled(!mState.value);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index fe504fe..3f0630d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -494,7 +494,7 @@
* onChildDismissed() calls.
*/
@Override
- public void onChildSnappedBack(View v) {
+ public void onChildSnappedBack(View v, float targetLeft) {
TaskView tv = (TaskView) v;
// Re-enable clipping with the stack
@@ -517,11 +517,6 @@
}
@Override
- public View getChildContentView(View v) {
- return v;
- }
-
- @Override
public boolean isAntiFalsingNeeded() {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 189e651..dd59fac 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -40,6 +40,7 @@
private DividerView mView;
private DockDividerVisibilityListener mDockDividerVisibilityListener;
private boolean mVisible = false;
+ private boolean mMinimized = false;
@Override
public void start() {
@@ -81,6 +82,10 @@
private void update(Configuration configuration) {
removeDivider();
addDivider(configuration);
+ if (mMinimized) {
+ mView.setMinimizedDockStack(true);
+ mWindowManager.setTouchable(false);
+ }
}
private void updateVisibility(final boolean visible) {
@@ -95,6 +100,23 @@
});
}
+ private void updateMinimizedDockedStack(final boolean minimized, final long animDuration) {
+ mView.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mMinimized != minimized) {
+ mMinimized = minimized;
+ mWindowManager.setTouchable(!minimized);
+ if (animDuration > 0) {
+ mView.setMinimizedDockStack(minimized, animDuration);
+ } else {
+ mView.setMinimizedDockStack(minimized);
+ }
+ }
+ }
+ });
+ }
+
class DockDividerVisibilityListener extends IDockedStackListener.Stub {
@Override
@@ -105,5 +127,11 @@
@Override
public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
}
+
+ @Override
+ public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
+ throws RemoteException {
+ updateMinimizedDockedStack(minimized, animDuration);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
index 36cfac8..9118e9c 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -140,4 +140,9 @@
canvas.drawRoundRect(left, top, left + mCurrentWidth, top + mCurrentHeight,
radius, radius, mPaint);
}
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 1bdf5a1..65a2f8f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -40,7 +40,6 @@
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import android.view.WindowInsets;
import android.view.WindowManager;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
@@ -86,6 +85,11 @@
*/
private static final float BOTTOM_RIGHT_SWITCH_BIGGER_FRACTION = 0.2f;
+ /**
+ * How much the background gets scaled when we are in the minimized dock state.
+ */
+ private static final float MINIMIZE_DOCK_SCALE = 0.375f;
+
private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
private static final PathInterpolator DIM_INTERPOLATOR =
@@ -126,6 +130,7 @@
private boolean mAnimateAfterRecentsDrawn;
private boolean mGrowAfterRecentsDrawn;
private boolean mGrowRecents;
+ private Animator mCurrentAnimator;
public DividerView(Context context) {
super(context);
@@ -205,6 +210,7 @@
}
public boolean startDragging(boolean animate, boolean touching) {
+ cancelFlingAnimation();
if (touching) {
mHandle.setTouching(true, animate);
}
@@ -364,11 +370,19 @@
commitSnapFlags(snapTarget);
mWindowManagerProxy.setResizing(false);
mDockSide = WindowManager.DOCKED_INVALID;
+ mCurrentAnimator = null;
}
});
+ mCurrentAnimator = anim;
return anim;
}
+ private void cancelFlingAnimation() {
+ if (mCurrentAnimator != null) {
+ mCurrentAnimator.cancel();
+ }
+ }
+
private void commitSnapFlags(SnapTarget target) {
if (target.flag == SnapTarget.FLAG_NONE) {
return;
@@ -433,6 +447,47 @@
mBackgroundLifted = false;
}
+
+ public void setMinimizedDockStack(boolean minimized) {
+ updateDockSide();
+ mHandle.setAlpha(minimized ? 0f : 1f);
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ mBackground.setPivotY(0);
+ mBackground.setScaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ } else if (mDockSide == WindowManager.DOCKED_LEFT
+ || mDockSide == WindowManager.DOCKED_RIGHT) {
+ mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
+ ? 0
+ : mBackground.getWidth());
+ mBackground.setScaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ }
+ }
+
+ public void setMinimizedDockStack(boolean minimized, long animDuration) {
+ updateDockSide();
+ mHandle.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setDuration(animDuration)
+ .alpha(minimized ? 0f : 1f)
+ .start();
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ mBackground.setPivotY(0);
+ mBackground.animate()
+ .scaleY(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ } else if (mDockSide == WindowManager.DOCKED_LEFT
+ || mDockSide == WindowManager.DOCKED_RIGHT) {
+ mBackground.setPivotX(mDockSide == WindowManager.DOCKED_LEFT
+ ? 0
+ : mBackground.getWidth());
+ mBackground.animate()
+ .scaleX(minimized ? MINIMIZE_DOCK_SCALE : 1f);
+ }
+ mBackground.animate()
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setDuration(animDuration)
+ .start();
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 2294d40..3db03d0 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -22,6 +22,7 @@
import android.view.WindowManager;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
@@ -79,4 +80,18 @@
mWindowManager.updateViewLayout(mView, mLp);
}
}
+
+ public void setTouchable(boolean touchable) {
+ boolean changed = false;
+ if (!touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) == 0) {
+ mLp.flags |= FLAG_NOT_TOUCHABLE;
+ changed = true;
+ } else if (touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) != 0) {
+ mLp.flags &= ~FLAG_NOT_TOUCHABLE;
+ changed = true;
+ }
+ if (changed) {
+ mWindowManager.updateViewLayout(mView, mLp);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 874defa..315c509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -208,6 +208,10 @@
return false;
}
+ protected boolean handleSlideBack() {
+ return false;
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result;
@@ -260,6 +264,9 @@
break;
case MotionEvent.ACTION_UP:
if (isWithinTouchSlop(event)) {
+ if (handleSlideBack()) {
+ return true;
+ }
if (!mActivated) {
makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2bebac2..ea8b75e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -103,6 +103,7 @@
import com.android.systemui.statusbar.policy.PreviewInflater;
import com.android.systemui.statusbar.policy.RemoteInputView;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.GearDisplayedListener;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import java.util.ArrayList;
@@ -115,7 +116,7 @@
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
- ExpandableNotificationRow.OnExpandClickListener {
+ ExpandableNotificationRow.OnExpandClickListener, GearDisplayedListener {
public static final String TAG = "StatusBar";
public static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
@@ -220,6 +221,7 @@
// which notification is currently being longpress-examined by the user
private NotificationGuts mNotificationGutsExposed;
+ private ExpandableNotificationRow mNotificationGearDisplayed;
private KeyboardShortcuts mKeyboardShortcuts;
@@ -1008,6 +1010,10 @@
guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey()));
}
+ protected GearDisplayedListener getGearDisplayedListener() {
+ return this;
+ }
+
protected SwipeHelper.LongPressListener getNotificationLongClicker() {
return new SwipeHelper.LongPressListener() {
@Override
@@ -1020,7 +1026,7 @@
return false;
}
- ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
bindGuts(row);
// Assume we are a status_bar_notification_row
@@ -1052,6 +1058,14 @@
= ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ a.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ // Move the notification view back over the gear
+ row.resetTranslation();
+ }
+ });
a.start();
guts.setExposed(true);
mStackScroller.onHeightChanged(null, true /* needsAnimation */);
@@ -1063,6 +1077,11 @@
};
}
+ @Override
+ public void onGearDisplayed(ExpandableNotificationRow row) {
+ mNotificationGearDisplayed = row;
+ }
+
public void dismissPopups() {
dismissPopups(-1, -1);
}
@@ -1095,6 +1114,11 @@
v.setExposed(false);
mStackScroller.onHeightChanged(null, true /* needsAnimation */);
}
+
+ if (mNotificationGearDisplayed != null) {
+ mNotificationGearDisplayed.resetTranslation();
+ mNotificationGearDisplayed = null;
+ }
}
@Override
@@ -1633,6 +1657,12 @@
return;
}
+ // Check if the notification is displaying the gear, if so slide notification back
+ if (row.getSettingsRow() != null && row.getSettingsRow().isVisible()) {
+ row.animateTranslateNotification(0);
+ return;
+ }
+
Notification notification = sbn.getNotification();
final PendingIntent intent = notification.contentIntent != null
? notification.contentIntent
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 7422902e..c73e115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,6 +16,12 @@
package com.android.systemui.statusbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Notification;
import android.content.Context;
import android.graphics.drawable.AnimatedVectorDrawable;
@@ -45,6 +51,7 @@
import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.statusbar.stack.StackViewState;
+import java.util.ArrayList;
import java.util.List;
public class ExpandableNotificationRow extends ActivatableNotificationView {
@@ -87,6 +94,8 @@
*/
private boolean mOnKeyguard;
+ private AnimatorSet mTranslateAnim;
+ private ArrayList<View> mTranslateableViews;
private NotificationContentView mPublicLayout;
private NotificationContentView mPrivateLayout;
private int mMaxExpandHeight;
@@ -96,6 +105,7 @@
private ExpansionLogger mLogger;
private String mLoggingKey;
private boolean mWasReset;
+ private NotificationSettingsIconRow mSettingsIconRow;
private NotificationGuts mGuts;
private NotificationData.Entry mEntry;
private StatusBarNotification mStatusBarNotification;
@@ -108,6 +118,7 @@
private boolean mChildrenExpanded;
private boolean mIsSummaryWithChildren;
private NotificationChildrenContainer mChildrenContainer;
+ private ViewStub mSettingsIconRowStub;
private ViewStub mGutsStub;
private boolean mIsSystemChildExpanded;
private boolean mIsPinned;
@@ -240,7 +251,6 @@
!= com.android.internal.R.id.status_bar_latest_event_content;
int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
: mMaxHeadsUpHeight;
- mMaxViewHeight = mNotificationMaxHeight;
mPrivateLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
mPublicLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
}
@@ -329,6 +339,15 @@
}
@Override
+ protected boolean handleSlideBack() {
+ if (mSettingsIconRow != null && mSettingsIconRow.isVisible()) {
+ animateTranslateNotification(0 /* targetLeft */);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
protected boolean shouldHideBackground() {
return super.shouldHideBackground() || mShowNoBackground;
}
@@ -500,6 +519,13 @@
return mPrivateLayout.getNotificationHeader();
}
+ private NotificationHeaderView getVisibleNotificationHeader() {
+ if (mNotificationHeader != null) {
+ return mNotificationHeader;
+ }
+ return getShowingLayout().getVisibleNotificationHeader();
+ }
+
public void setOnExpandClickListener(OnExpandClickListener onExpandClickListener) {
mOnExpandClickListener = onExpandClickListener;
}
@@ -527,6 +553,17 @@
mGuts.setVisibility(oldGuts.getVisibility());
addView(mGuts, index);
}
+ if (mSettingsIconRow != null) {
+ View oldSettings = mSettingsIconRow;
+ int settingsIndex = indexOfChild(oldSettings);
+ removeView(oldSettings);
+ mSettingsIconRow = (NotificationSettingsIconRow) LayoutInflater.from(mContext).inflate(
+ R.layout.notification_settings_icon_row, this, false);
+ mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
+ mSettingsIconRow.setVisibility(oldSettings.getVisibility());
+ addView(mSettingsIconRow, settingsIndex);
+
+ }
mPrivateLayout.reInflateViews();
mPublicLayout.reInflateViews();
}
@@ -542,16 +579,23 @@
}
private void initDimens() {
- mNotificationMinHeightLegacy = getResources().getDimensionPixelSize(
- R.dimen.notification_min_height_legacy);
- mNotificationMinHeight = getResources().getDimensionPixelSize(
- R.dimen.notification_min_height);
- mNotificationMaxHeight = getResources().getDimensionPixelSize(
- R.dimen.notification_max_height);
- mMaxHeadsUpHeightLegacy = getResources().getDimensionPixelSize(
+ mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
+ mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
+ mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
+ mMaxHeadsUpHeightLegacy = getFontScaledHeight(
R.dimen.notification_max_heads_up_height_legacy);
- mMaxHeadsUpHeight = getResources().getDimensionPixelSize(
- R.dimen.notification_max_heads_up_height);
+ mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
+ }
+
+ /**
+ * @param dimenId the dimen to look up
+ * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
+ */
+ private int getFontScaledHeight(int dimenId) {
+ int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
+ float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
+ getResources().getDisplayMetrics().density);
+ return (int) (dimensionPixelSize * factor);
}
/**
@@ -561,7 +605,6 @@
public void reset() {
super.reset();
final boolean wasExpanded = isExpanded();
- mMaxViewHeight = 0;
mExpandable = false;
mHasUserChangedExpansion = false;
mUserLocked = false;
@@ -573,6 +616,7 @@
mPublicLayout.reset(mIsHeadsUp);
mPrivateLayout.reset(mIsHeadsUp);
resetHeight();
+ resetTranslation();
logExpansionEvent(false, wasExpanded);
}
@@ -596,6 +640,14 @@
mPrivateLayout.setExpandClickListener(mExpandClickListener);
mPrivateLayout.setContainingNotification(this);
mPublicLayout.setExpandClickListener(mExpandClickListener);
+ mSettingsIconRowStub = (ViewStub) findViewById(R.id.settings_icon_row_stub);
+ mSettingsIconRowStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+ @Override
+ public void onInflate(ViewStub stub, View inflated) {
+ mSettingsIconRow = (NotificationSettingsIconRow) inflated;
+ mSettingsIconRow.setNotificationRowParent(ExpandableNotificationRow.this);
+ }
+ });
mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
@@ -603,6 +655,7 @@
mGuts = (NotificationGuts) inflated;
mGuts.setClipTopAmount(getClipTopAmount());
mGuts.setActualHeight(getActualHeight());
+ mTranslateableViews.add(mGuts);
mGutsStub = null;
}
});
@@ -613,9 +666,89 @@
public void onInflate(ViewStub stub, View inflated) {
mChildrenContainer = (NotificationChildrenContainer) inflated;
mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
+ mTranslateableViews.add(mChildrenContainer);
}
});
mVetoButton = findViewById(R.id.veto);
+
+ // Add the views that we translate to reveal the gear
+ mTranslateableViews = new ArrayList<View>();
+ for (int i = 0; i < getChildCount(); i++) {
+ mTranslateableViews.add(getChildAt(i));
+ }
+ // Remove views that don't translate
+ mTranslateableViews.remove(mVetoButton);
+ mTranslateableViews.remove(mSettingsIconRowStub);
+ mTranslateableViews.remove(mChildrenContainerStub);
+ mTranslateableViews.remove(mGutsStub);
+ }
+
+ public void setTranslationForOutline(float translationX) {
+ setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
+ }
+
+ public void resetTranslation() {
+ if (mTranslateableViews != null) {
+ for (int i = 0; i < mTranslateableViews.size(); i++) {
+ mTranslateableViews.get(i).setTranslationX(0);
+ }
+ setTranslationForOutline(0);
+ }
+ if (mSettingsIconRow != null) {
+ mSettingsIconRow.resetState();
+ }
+ }
+
+ public void animateTranslateNotification(final float leftTarget) {
+ if (mTranslateAnim != null) {
+ mTranslateAnim.cancel();
+ }
+ AnimatorSet set = new AnimatorSet();
+ if (mTranslateableViews != null) {
+ for (int i = 0; i < mTranslateableViews.size(); i++) {
+ final View animView = mTranslateableViews.get(i);
+ final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(
+ animView, "translationX", leftTarget);
+ if (i == 0) {
+ translateAnim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setTranslationForOutline((float) animation.getAnimatedValue());
+ }
+ });
+ }
+ translateAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator anim) {
+ if (mSettingsIconRow != null && leftTarget == 0) {
+ mSettingsIconRow.resetState();
+ }
+ mTranslateAnim = null;
+ }
+ });
+ set.play(translateAnim);
+ }
+ }
+ mTranslateAnim = set;
+ set.start();
+ }
+
+ public float getSpaceForGear() {
+ if (mSettingsIconRow != null) {
+ return mSettingsIconRow.getSpaceForGear();
+ }
+ return 0;
+ }
+
+ public NotificationSettingsIconRow getSettingsRow() {
+ if (mSettingsIconRow == null) {
+ mSettingsIconRowStub.inflate();
+ }
+ return mSettingsIconRow;
+ }
+
+ public ArrayList<View> getContentViews() {
+ return mTranslateableViews;
}
public void inflateGuts() {
@@ -772,7 +905,7 @@
if (mIsSummaryWithChildren) {
mChildrenContainer.updateGroupOverflow();
}
- notifyHeightChanged(false /* needsAnimation */);
+ notifyHeightChanged(false /* needsAnimation */);
}
}
}
@@ -1097,6 +1230,7 @@
mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
mNotificationHeader);
addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
+ mTranslateableViews.add(mNotificationHeader);
} else {
header.reapply(getContext(), mNotificationHeader);
mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
@@ -1166,7 +1300,7 @@
protected boolean disallowSingleClick(MotionEvent event) {
float x = event.getX();
float y = event.getY();
- NotificationHeaderView header = getNotificationHeader();
+ NotificationHeaderView header = getVisibleNotificationHeader();
if (header != null) {
return header.isInTouchRect(x, y);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 44c6a5d..782a38c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -81,8 +81,13 @@
}
protected void setOutlineRect(float left, float top, float right, float bottom) {
+ setOutlineRect(true, left, top, right, bottom);
+ }
+
+ protected void setOutlineRect(boolean clipToOutline, float left, float top, float right,
+ float bottom) {
mCustomOutline = true;
- setClipToOutline(true);
+ setClipToOutline(clipToOutline);
mOutlineRect.set((int) left, (int) top, (int) right, (int) bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 8042b60..3176e2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -24,7 +24,6 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import com.android.systemui.R;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
@@ -35,7 +34,6 @@
public abstract class ExpandableView extends FrameLayout {
protected OnHeightChangedListener mOnHeightChangedListener;
- protected int mMaxViewHeight;
private int mActualHeight;
protected int mClipTopAmount;
private boolean mActualHeightInitialized;
@@ -49,8 +47,6 @@
public ExpandableView(Context context, AttributeSet attrs) {
super(context, attrs);
- mMaxViewHeight = getResources().getDimensionPixelSize(
- R.dimen.notification_max_height);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index d5361dd..647f0bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -144,11 +144,11 @@
}
if (mContractedChild != null) {
int heightSpec;
+ int size = Math.min(maxSize, mSmallHeight);
if (shouldContractedBeFixedSize()) {
- int size = Math.min(maxSize, mSmallHeight);
heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
} else {
- heightSpec = MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST);
+ heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
}
mContractedChild.measure(widthMeasureSpec, heightSpec);
int measuredHeight = mContractedChild.getMeasuredHeight();
@@ -475,6 +475,19 @@
}
}
+ private NotificationViewWrapper getCurrentVisibleWrapper() {
+ switch (mVisibleType) {
+ case VISIBLE_TYPE_EXPANDED:
+ return mExpandedWrapper;
+ case VISIBLE_TYPE_HEADSUP:
+ return mHeadsUpWrapper;
+ case VISIBLE_TYPE_CONTRACTED:
+ return mContractedWrapper;
+ default:
+ return null;
+ }
+ }
+
/**
* @return one of the static enum types in this view, calculated form the current state
*/
@@ -684,6 +697,11 @@
return header;
}
+ public NotificationHeaderView getVisibleNotificationHeader() {
+ NotificationViewWrapper wrapper = getCurrentVisibleWrapper();
+ return wrapper == null ? null : wrapper.getNotificationHeader();
+ }
+
public void setContainingNotification(ExpandableNotificationRow containingNotification) {
mContainingNotification = containingNotification;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 2cacb8a..ccd0ad8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -34,6 +34,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Objects;
/**
* The list of currently displaying notifications.
@@ -118,10 +119,16 @@
final RemoteViews newPublicNotification
= updatedNotificationBuilder.makePublicContentView();
+ boolean sameCustomView = Objects.equals(
+ notification.getNotification().extras.getBoolean(
+ Notification.EXTRA_CONTAINS_CUSTOM_VIEW),
+ updatedNotification.extras.getBoolean(
+ Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
applyInPlace = compareRemoteViews(cachedContentView, newContentView)
&& compareRemoteViews(cachedBigContentView, newBigContentView)
&& compareRemoteViews(cachedHeadsUpContentView, newHeadsUpContentView)
- && compareRemoteViews(cachedPublicContentView, newPublicNotification);
+ && compareRemoteViews(cachedPublicContentView, newPublicNotification)
+ && sameCustomView;
cachedPublicContentView = newPublicNotification;
cachedHeadsUpContentView = newHeadsUpContentView;
cachedBigContentView = newBigContentView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 7346bec..fe84d813 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -49,9 +49,7 @@
private int mClipTopAmount;
private int mActualHeight;
private boolean mExposed;
- private RadioButton mApplyToTopic;
private SeekBar mSeekBar;
- private Notification.Topic mTopic;
private INotificationManager mINotificationManager;
private int mStartingImportance;
@@ -109,24 +107,9 @@
mStartingImportance = importance;
mINotificationManager = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- mTopic = sbn.getNotification().getTopic() == null
- ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
- com.android.internal.R.string.default_notification_topic_label))
- : sbn.getNotification().getTopic();
- boolean doesUserUseTopics = false;
- try {
- doesUserUseTopics =
- mINotificationManager.doesUserUseTopics(sbn.getPackageName(), sbn.getUid());
- } catch (RemoteException e) {}
- final boolean userUsesTopics = doesUserUseTopics;
- mApplyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic);
- if (userUsesTopics) {
- mApplyToTopic.setChecked(true);
- }
- final View applyToApp = row.findViewById(R.id.apply_to_app);
- final TextView topicSummary = ((TextView) row.findViewById(R.id.summary));
- final TextView topicTitle = ((TextView) row.findViewById(R.id.title));
+ final TextView importanceSummary = ((TextView) row.findViewById(R.id.summary));
+ final TextView importanceTitle = ((TextView) row.findViewById(R.id.title));
mSeekBar = (SeekBar) row.findViewById(R.id.seekbar);
boolean systemApp = false;
try {
@@ -156,12 +139,6 @@
updateTitleAndSummary(progress);
if (fromUser) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_MODIFY_IMPORTANCE_SLIDER);
- if (userUsesTopics) {
- mApplyToTopic.setVisibility(View.VISIBLE);
- mApplyToTopic.setText(
- mContext.getString(R.string.apply_to_topic, mTopic.getLabel()));
- applyToApp.setVisibility(View.VISIBLE);
- }
}
}
@@ -178,29 +155,29 @@
private void updateTitleAndSummary(int progress) {
switch (progress) {
case NotificationListenerService.Ranking.IMPORTANCE_NONE:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_blocked));
- topicTitle.setText(mContext.getString(R.string.blocked_importance));
+ importanceTitle.setText(mContext.getString(R.string.blocked_importance));
break;
case NotificationListenerService.Ranking.IMPORTANCE_LOW:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_low));
- topicTitle.setText(mContext.getString(R.string.low_importance));
+ importanceTitle.setText(mContext.getString(R.string.low_importance));
break;
case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_default));
- topicTitle.setText(mContext.getString(R.string.default_importance));
+ importanceTitle.setText(mContext.getString(R.string.default_importance));
break;
case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_high));
- topicTitle.setText(mContext.getString(R.string.high_importance));
+ importanceTitle.setText(mContext.getString(R.string.high_importance));
break;
case NotificationListenerService.Ranking.IMPORTANCE_MAX:
- topicSummary.setText(mContext.getString(
+ importanceSummary.setText(mContext.getString(
R.string.notification_importance_max));
- topicTitle.setText(mContext.getString(R.string.max_importance));
+ importanceTitle.setText(mContext.getString(R.string.max_importance));
break;
}
}
@@ -213,8 +190,7 @@
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
progress - mStartingImportance);
try {
- mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(),
- mApplyToTopic.isChecked() ? mTopic : null, progress);
+ mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(), progress);
} catch (RemoteException e) {
// :(
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
new file mode 100644
index 0000000..4491ebd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+
+public class NotificationSettingsIconRow extends FrameLayout implements View.OnClickListener {
+
+ public interface SettingsIconRowListener {
+ /**
+ * Called when the gear behind a notification is touched.
+ */
+ public void onGearTouched(ExpandableNotificationRow row);
+ }
+
+ private ExpandableNotificationRow mParent;
+ private AlphaOptimizedImageView mGearIcon;
+ private float mHorizSpaceForGear;
+ private SettingsIconRowListener mListener;
+
+ private ValueAnimator mFadeAnimator;
+ private boolean mSettingsFadedIn = false;
+ private boolean mAnimating = false;
+ private boolean mOnLeft = true;
+
+ public NotificationSettingsIconRow(Context context) {
+ this(context, null);
+ }
+
+ public NotificationSettingsIconRow(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public NotificationSettingsIconRow(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mGearIcon = (AlphaOptimizedImageView) findViewById(R.id.gear_icon);
+ mGearIcon.setOnClickListener(this);
+ setOnClickListener(this);
+ mHorizSpaceForGear =
+ getResources().getDimensionPixelOffset(R.dimen.notification_gear_width);
+ resetState();
+ }
+
+ public void setGearListener(SettingsIconRowListener listener) {
+ mListener = listener;
+ }
+
+ public void setNotificationRowParent(ExpandableNotificationRow parent) {
+ mParent = parent;
+ }
+
+ public ExpandableNotificationRow getNotificationParent() {
+ return mParent;
+ }
+
+ public void resetState() {
+ setGearAlpha(0f);
+ mAnimating = false;
+ setIconLocation(true /* on left */);
+ }
+
+ private void setGearAlpha(float alpha) {
+ if (alpha == 0) {
+ mSettingsFadedIn = false; // Can fade in again once it's gone.
+ mGearIcon.setVisibility(View.INVISIBLE);
+ } else {
+ if (alpha == 1) {
+ mSettingsFadedIn = true;
+ }
+ mGearIcon.setVisibility(View.VISIBLE);
+ }
+ mGearIcon.setAlpha(alpha);
+ }
+
+ /**
+ * Returns the horizontal space in pixels required to display the gear behind a notification.
+ */
+ public float getSpaceForGear() {
+ return mHorizSpaceForGear;
+ }
+
+ /**
+ * Indicates whether the gear is visible at 1 alpha. Does not indicate
+ * if entire view is visible.
+ */
+ public boolean isVisible() {
+ return mSettingsFadedIn;
+ }
+
+ public void cancelFadeAnimator() {
+ if (mFadeAnimator != null) {
+ mFadeAnimator.cancel();
+ }
+ }
+
+ public void updateSettingsIcons(final float transX, final float size) {
+ if (mAnimating || (mGearIcon.getAlpha() == 0)) {
+ // Don't adjust when animating or settings aren't visible
+ return;
+ }
+ setIconLocation(transX > 0 /* fromLeft */);
+ final float fadeThreshold = size * 0.3f;
+ final float absTrans = Math.abs(transX);
+ float desiredAlpha = 0;
+
+ if (absTrans <= fadeThreshold) {
+ desiredAlpha = 1;
+ } else {
+ desiredAlpha = 1 - ((absTrans - fadeThreshold) / (size - fadeThreshold));
+ }
+ setGearAlpha(desiredAlpha);
+ }
+
+ public void fadeInSettings(final boolean fromLeft, final float transX,
+ final float notiThreshold) {
+ setIconLocation(transX > 0 /* fromLeft */);
+ mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
+ mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float absTrans = Math.abs(transX);
+
+ boolean pastGear = (fromLeft && transX <= notiThreshold)
+ || (!fromLeft && absTrans <= notiThreshold);
+ if (pastGear && !mSettingsFadedIn) {
+ setGearAlpha((float) animation.getAnimatedValue());
+ }
+ }
+ });
+ mFadeAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ mAnimating = false;
+ mSettingsFadedIn = false;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mAnimating = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mAnimating = false;
+ mSettingsFadedIn = true;
+ }
+ });
+ mFadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
+ mFadeAnimator.setDuration(200);
+ mFadeAnimator.start();
+ }
+
+ private void setIconLocation(boolean onLeft) {
+ if (onLeft == mOnLeft) {
+ // Same side? Do nothing.
+ return;
+ }
+
+ setTranslationX(onLeft ? 0 : (mParent.getWidth() - mHorizSpaceForGear));
+ mOnLeft = onLeft;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v.getId() == R.id.gear_icon) {
+ if (mListener != null) {
+ mListener.onGearTouched(mParent);
+ }
+ } else {
+ // Do nothing when the background is touched.
+ }
+ }
+}
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 a58fa86..8a93c5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -23,6 +23,7 @@
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.support.v4.util.SimpleArrayMap;
+import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.LinearLayout;
@@ -71,6 +72,7 @@
private int mCurrentFacetIndex;
private String mCurrentPackageName;
+ private SparseBooleanArray mFacetHasMultipleAppsCache = new SparseBooleanArray();
public CarNavigationBarController(Context context,
CarNavigationBarView navBar,
@@ -96,6 +98,21 @@
}
}
+ public void onPackageChange(String packageName) {
+ if (mFacetPackageMap.containsKey(packageName)) {
+ int index = mFacetPackageMap.get(packageName);
+ mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
+ // No need to check categories because we've already refreshed the cache.
+ return;
+ }
+
+ String category = getPackageCategory(packageName);
+ if (mFacetCategoryMap.containsKey(category)) {
+ int index = mFacetCategoryMap.get(packageName);
+ mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
+ }
+ }
+
private void bind() {
// Read up arrays_car.xml and populate the navigation bar here.
Resources r = mContext.getResources();
@@ -138,6 +155,7 @@
initFacetFilterMaps(i,
facetPackageNames.getString(i).split(FACET_FILTER_DEMILITER),
facetCategories.getString(i).split(FACET_FILTER_DEMILITER));
+ mFacetHasMultipleAppsCache.put(i, facetHasMultiplePackages(i));
} catch (URISyntaxException e) {
throw new RuntimeException("Malformed intent uri", e);
}
@@ -229,7 +247,7 @@
if (mNavButtons.get(index) != null) {
mNavButtons.get(index).setSelected(true /* selected */,
- facetHasMultiplePackages(index) /* showMoreIcon */);
+ mFacetHasMultipleAppsCache.get(index) /* showMoreIcon */);
}
mCurrentFacetIndex = index;
}
@@ -268,7 +286,7 @@
private void startActivity(Intent intent) {
if (mActivityStarter != null && intent != null) {
- mActivityStarter.startActivity(intent, true);
+ mActivityStarter.startActivity(intent, false);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 08cd053..c32ef0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -18,7 +18,10 @@
import android.app.ActivityManager;
import android.app.ITaskStackListener;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Looper;
@@ -52,6 +55,7 @@
mTaskStackListener = new TaskStackListenerImpl(mHandler);
mSystemServicesProxy = new SystemServicesProxy(mContext);
mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+ registerPackageChangeReceivers();
}
@Override
@@ -81,6 +85,26 @@
mController = new CarNavigationBarController(context, mCarNavigationBar,
this /* ActivityStarter*/);
mNavigationBarView = mCarNavigationBar;
+
+ }
+
+ private BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getData() == null || mController == null) {
+ return;
+ }
+ String packageName = intent.getData().getSchemeSpecificPart();
+ mController.onPackageChange(packageName);
+ }
+ };
+
+ private void registerPackageChangeReceivers() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(mPackageChangeReceiver, filter);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.java
new file mode 100644
index 0000000..8c7c71f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandableIndicator.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 com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import com.android.systemui.R;
+
+public class ExpandableIndicator extends ImageView {
+
+ private boolean mExpanded;
+
+ public ExpandableIndicator(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
+ : R.drawable.ic_volume_expand_animation;
+ setImageResource(res);
+ }
+
+ public void setExpanded(boolean expanded) {
+ if (expanded == mExpanded) return;
+ mExpanded = expanded;
+ final int res = mExpanded ? R.drawable.ic_volume_expand_animation
+ : R.drawable.ic_volume_collapse_animation;
+ // workaround to reset drawable
+ final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext()
+ .getDrawable(res).getConstantState().newDrawable();
+ setImageDrawable(avd);
+ avd.start();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
new file mode 100644
index 0000000..4f3c61e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenWallpaper.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.app.ActivityManager;
+import android.app.IWallpaperManager;
+import android.app.IWallpaperManagerCallback;
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+/**
+ * Manages the lockscreen wallpaper.
+ */
+public class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implements Runnable {
+
+ private static final String TAG = "LockscreenWallpaper";
+
+ private final Context mContext;
+ private final PhoneStatusBar mBar;
+ private final IWallpaperManager mService;
+ private final Handler mH;
+
+ private boolean mCached;
+ private Bitmap mCache;
+ private int mUserId;
+
+ public LockscreenWallpaper(Context ctx, PhoneStatusBar bar, Handler h) {
+ mContext = ctx;
+ mBar = bar;
+ mH = h;
+ mService = IWallpaperManager.Stub.asInterface(
+ ServiceManager.getService(Context.WALLPAPER_SERVICE));
+ mUserId = ActivityManager.getCurrentUser();
+
+ try {
+ mService.setLockWallpaperCallback(this);
+ } catch (RemoteException e) {
+ Log.e(TAG, "System dead?" + e);
+ }
+ }
+
+ public Bitmap getBitmap() {
+ try {
+ if (mCached) {
+ return mCache;
+ }
+ if (!mService.isWallpaperSupported(mContext.getOpPackageName())) {
+ mCached = true;
+ mCache = null;
+ return null;
+ }
+ ParcelFileDescriptor fd = mService.getWallpaper(null, WallpaperManager.FLAG_SET_LOCK,
+ new Bundle(), mUserId);
+ if (fd != null) {
+ try {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ mCache = BitmapFactory.decodeFileDescriptor(
+ fd.getFileDescriptor(), null, options);
+ mCached = true;
+ return mCache;
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Can't decode file", e);
+ return null;
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ } else {
+ mCached = true;
+ mCache = null;
+ return null;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "System dead?" + e);
+ return null;
+ }
+ }
+
+ public void setUser(int user) {
+ if (user != mUserId) {
+ mCached = false;
+ mUserId = user;
+ }
+ }
+
+ @Override
+ public void onWallpaperChanged() {
+ // Called on Binder thread.
+ mH.removeCallbacks(this);
+ mH.post(this);
+ }
+
+ @Override
+ public void run() {
+ // Called in response to onWallpaperChanged on the main thread.
+ mCached = false;
+ mCache = null;
+ getBitmap();
+ mBar.updateMediaMetaData(true /* metaDataChanged */, true /* allowEnterAnimation */);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index d625fc2..260c969 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -163,68 +163,29 @@
String[] start = sets[0].split(BUTTON_SEPARATOR);
String[] center = sets[1].split(BUTTON_SEPARATOR);
String[] end = sets[2].split(BUTTON_SEPARATOR);
- inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group),
- (ViewGroup) mRot0.findViewById(R.id.ends_group_lightsout), false);
- inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group),
- (ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
+ inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
+ inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
- inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group),
- (ViewGroup) mRot0.findViewById(R.id.center_group_lightsout), false);
- inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group),
- (ViewGroup) mRot90.findViewById(R.id.center_group_lightsout), true);
+ inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group), false);
+ inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group), true);
addGravitySpacer((LinearLayout) mRot0.findViewById(R.id.ends_group));
addGravitySpacer((LinearLayout) mRot90.findViewById(R.id.ends_group));
- inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group),
- (ViewGroup) mRot0.findViewById(R.id.ends_group_lightsout), false);
- inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group),
- (ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
+ inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
+ inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
}
private void addGravitySpacer(LinearLayout layout) {
layout.addView(new Space(mContext), new LinearLayout.LayoutParams(0, 0, 1));
}
- private void inflateButtons(String[] buttons, ViewGroup parent, ViewGroup lightsOutParent,
- boolean landscape) {
+ private void inflateButtons(String[] buttons, ViewGroup parent, boolean landscape) {
for (int i = 0; i < buttons.length; i++) {
- copyToLightsout(inflateButton(buttons[i], parent, landscape), lightsOutParent);
+ inflateButton(buttons[i], parent, landscape);
}
}
- private void copyToLightsout(View view, ViewGroup lightsOutParent) {
- if (view == null) return;
-
- if (view instanceof FrameLayout) {
- // The only ViewGroup we support in here is a FrameLayout, so copy those manually.
- FrameLayout original = (FrameLayout) view;
- FrameLayout layout = new FrameLayout(view.getContext());
- for (int i = 0; i < original.getChildCount(); i++) {
- copyToLightsout(original.getChildAt(i), layout);
- }
- lightsOutParent.addView(layout, copy(view.getLayoutParams()));
- } else if (view instanceof Space) {
- lightsOutParent.addView(new Space(view.getContext()), copy(view.getLayoutParams()));
- } else {
- lightsOutParent.addView(generateLightsOutView(view), copy(view.getLayoutParams()));
- }
- }
-
- private View generateLightsOutView(View view) {
- ImageView imageView = new ImageView(view.getContext());
- // Copy everything we can about the original view.
- imageView.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
- view.getPaddingBottom());
- imageView.setContentDescription(view.getContentDescription());
- imageView.setId(view.getId());
- // Only home gets a big dot, everything else will be little.
- imageView.setImageResource(view.getId() == R.id.home
- ? R.drawable.ic_sysbar_lights_out_dot_large
- : R.drawable.ic_sysbar_lights_out_dot_small);
- return imageView;
- }
-
private ViewGroup.LayoutParams copy(ViewGroup.LayoutParams layoutParams) {
if (layoutParams instanceof LinearLayout.LayoutParams) {
return new LinearLayout.LayoutParams(layoutParams.width, layoutParams.height,
@@ -348,9 +309,7 @@
}
}
clearAllChildren((ViewGroup) mRot0.findViewById(R.id.nav_buttons));
- clearAllChildren((ViewGroup) mRot0.findViewById(R.id.lights_out));
clearAllChildren((ViewGroup) mRot90.findViewById(R.id.nav_buttons));
- clearAllChildren((ViewGroup) mRot90.findViewById(R.id.lights_out));
}
private void clearAllChildren(ViewGroup group) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 134c579..1fe0115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -64,42 +64,20 @@
mLightsOut = lightsOut;
final View navButtons = mView.getCurrentView().findViewById(R.id.nav_buttons);
- final View lowLights = mView.getCurrentView().findViewById(R.id.lights_out);
// ok, everyone, stop it right there
navButtons.animate().cancel();
- lowLights.animate().cancel();
- final float navButtonsAlpha = lightsOut ? 0f : 1f;
- final float lowLightsAlpha = lightsOut ? 1f : 0f;
+ final float navButtonsAlpha = lightsOut ? 0.5f : 1f;
if (!animate) {
navButtons.setAlpha(navButtonsAlpha);
- lowLights.setAlpha(lowLightsAlpha);
- lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
} else {
final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
navButtons.animate()
.alpha(navButtonsAlpha)
.setDuration(duration)
.start();
-
- lowLights.setOnTouchListener(mLightsOutListener);
- if (lowLights.getVisibility() == View.GONE) {
- lowLights.setAlpha(0f);
- lowLights.setVisibility(View.VISIBLE);
- }
- lowLights.animate()
- .alpha(lowLightsAlpha)
- .setDuration(duration)
- .setInterpolator(new AccelerateInterpolator(2.0f))
- .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator _a) {
- lowLights.setVisibility(View.GONE);
- }
- })
- .start();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 97d7dd5..e53f044 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -79,7 +79,7 @@
private Drawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
private Drawable mHomeDefaultIcon, mHomeCarModeIcon;
private Drawable mRecentIcon;
- private Drawable mRecentLandIcon;
+ private Drawable mDockedIcon;
private NavigationBarGestureHelper mGestureHelper;
private DeadZone mDeadZone;
@@ -97,6 +97,7 @@
private boolean mLayoutTransitionsEnabled = true;
private boolean mWakeAndUnlocking;
private boolean mCarMode = false;
+ private boolean mDockedStackExists;
private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
@@ -280,7 +281,7 @@
mHomeDefaultIcon = ctx.getDrawable(R.drawable.ic_sysbar_home);
mRecentIcon = ctx.getDrawable(R.drawable.ic_sysbar_recent);
- mRecentLandIcon = mRecentIcon;
+ mDockedIcon = ctx.getDrawable(R.drawable.ic_sysbar_docked);
getCarModeIcons(ctx);
}
@@ -335,8 +336,7 @@
getBackButton().setImageDrawable(backIcon);
- getRecentsButton().setImageDrawable(
- mVertical ? mRecentLandIcon : mRecentIcon);
+ updateRecentsIcon();
if (mCarMode) {
getHomeButton().setImageDrawable(mHomeCarModeIcon);
@@ -507,20 +507,24 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- updateRecentsIcon(exists);
+ mDockedStackExists = exists;
+ updateRecentsIcon();
}
});
}
+
+ @Override
+ public void onDockedStackMinimizedChanged(boolean minimized, long animDuration)
+ throws RemoteException {
+ }
});
} catch (RemoteException e) {
Log.e(TAG, "Failed registering docked stack exists listener", e);
}
}
- private void updateRecentsIcon(boolean dockedStackExists) {
- getRecentsButton().setImageResource(dockedStackExists
- ? R.drawable.ic_sysbar_docked
- : R.drawable.ic_sysbar_recent);
+ private void updateRecentsIcon() {
+ getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
}
public boolean isVertical() {
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 3aa576f..1089852 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -23,6 +23,7 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
+import android.app.IWallpaperManagerCallback;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
@@ -115,7 +116,7 @@
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.qs.QSDetail;
+import com.android.systemui.qs.QSContainer;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.recents.events.EventBus;
@@ -248,9 +249,7 @@
private static final boolean ONLY_CORE_APPS;
/** If true, the lockscreen will show a distinct wallpaper */
- private static final boolean ENABLE_LOCKSCREEN_WALLPAPER =
- !ActivityManager.isLowRamDeviceStatic()
- && SystemProperties.getBoolean("debug.lockscreen_wallpaper", false);
+ private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
/* If true, the device supports freeform window management.
* This affects the status bar UI. */
@@ -296,6 +295,7 @@
AccessibilityController mAccessibilityController;
FingerprintUnlockController mFingerprintUnlockController;
LightStatusBarController mLightStatusBarController;
+ private LockscreenWallpaper mLockscreenWallpaper;
int mNaturalBarHeight = -1;
@@ -318,7 +318,7 @@
StatusBarIconController mIconController;
// expanded notifications
- NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
+ protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
View mExpandedContents;
TextView mNotificationPanelDebugText;
@@ -746,6 +746,7 @@
mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
R.id.notification_stack_scroller);
mStackScroller.setLongPressListener(getNotificationLongClicker());
+ mStackScroller.setGearDisplayedListener(getGearDisplayedListener());
mStackScroller.setPhoneStatusBar(this);
mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setHeadsUpManager(mHeadsUpManager);
@@ -792,6 +793,10 @@
mKeyguardBottomArea.getLockIcon());
mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
+ if (ENABLE_LOCKSCREEN_WALLPAPER) {
+ mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
+ }
+
// set the initial view visibility
setAreThereNotifications();
@@ -867,13 +872,12 @@
mCastController, mFlashlightController,
mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
mSecurityController, mBatteryController, mIconController);
- mQSPanel.setHost(qsh);
mQSPanel.setTiles(qsh.getTiles());
mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
- mHeader.setQSPanel(mQSPanel);
- QSDetail qsDetail = (QSDetail) mStatusBarWindow.findViewById(R.id.qs_detail);
- qsDetail.setHost(qsh);
+ QSContainer qsContainer = (QSContainer) mStatusBarWindow.findViewById(
+ R.id.quick_settings_container);
+ qsContainer.setHost(qsh);
qsh.addCallback(new QSTileHost.Callback() {
@Override
public void onTilesChanged() {
@@ -1819,7 +1823,7 @@
};
/**
- * Refresh or remove lockscreen artwork from media metadata.
+ * Refresh or remove lockscreen artwork from media metadata or the lockscreen wallpaper.
*/
public void updateMediaMetaData(boolean metaDataChanged, boolean allowEnterAnimation) {
if (!SHOW_LOCKSCREEN_MEDIA_ARTWORK) return;
@@ -1847,10 +1851,7 @@
}
}
if (ENABLE_LOCKSCREEN_WALLPAPER && artworkBitmap == null) {
- // TODO: use real lockscreen wallpaper.
- WallpaperManager wallpaperManager = mContext
- .getSystemService(WallpaperManager.class);
- artworkBitmap = wallpaperManager.getBitmap();
+ artworkBitmap = mLockscreenWallpaper.getBitmap();
}
final boolean hasArtwork = artworkBitmap != null;
@@ -3084,10 +3085,6 @@
else if (Intent.ACTION_SCREEN_ON.equals(action)) {
notifyNavigationBarScreenOn(true);
}
- else if (ENABLE_LOCKSCREEN_WALLPAPER
- && Intent.ACTION_WALLPAPER_CHANGED.equals(action)) {
- updateMediaMetaData(true, true);
- }
}
};
@@ -3173,6 +3170,7 @@
resetUserSetupObserver();
setControllerUsers();
clearCurrentMediaNotification();
+ mLockscreenWallpaper.setUser(newUserId);
updateMediaMetaData(true, false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index df5a622..6550c87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -456,11 +456,9 @@
mIconController.setIcon(mSlotRotate, R.drawable.stat_sys_rotate_landscape,
mContext.getString(R.string.accessibility_rotation_lock_on_landscape));
}
+ mIconController.setIconVisibility(mSlotRotate, true);
} else {
- mIconController.setIcon(mSlotRotate, portrait
- ? R.drawable.stat_sys_auto_rotate_portrait
- : R.drawable.stat_sys_auto_rotate_landscape,
- mContext.getString(R.string.accessibility_rotation_lock_off));
+ mIconController.setIconVisibility(mSlotRotate, false);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 2af2009..80afb9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -57,7 +57,7 @@
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.DisplayController;
+import com.android.systemui.statusbar.policy.NightModeController;
import com.android.systemui.statusbar.policy.FlashlightController;
import com.android.systemui.statusbar.policy.HotspotController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -68,7 +68,7 @@
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.tuner.ColorMatrixTile;
+import com.android.systemui.tuner.NightModeTile;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -108,7 +108,7 @@
private final TileServices mServices;
private final List<Callback> mCallbacks = new ArrayList<>();
- private final DisplayController mDisplayController;
+ private final NightModeController mNightModeController;
private final AutoTileManager mAutoTiles;
private final ManagedProfileController mProfileController;
private View mHeader;
@@ -137,7 +137,7 @@
mSecurity = security;
mBattery = battery;
mIconController = iconController;
- mDisplayController = new DisplayController(mContext);
+ mNightModeController = new NightModeController(mContext, true);
mProfileController = new ManagedProfileController(this);
final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
@@ -292,8 +292,8 @@
return mIconController;
}
- public DisplayController getDisplayController() {
- return mDisplayController;
+ public NightModeController getNightModeController() {
+ return mNightModeController;
}
public ManagedProfileController getManagedProfileController() {
@@ -422,8 +422,8 @@
else if (tileSpec.equals("user")) return new UserTile(this);
else if (tileSpec.equals("battery")) return new BatteryTile(this);
else if (tileSpec.equals("saver")) return new DataSaverTile(this);
- else if (tileSpec.equals(ColorMatrixTile.COLOR_MATRIX_SPEC))
- return new ColorMatrixTile(this);
+ else if (tileSpec.equals(NightModeTile.NIGHT_MODE_SPEC))
+ return new NightModeTile(this);
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 3bb141a..ab8067d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -26,6 +26,7 @@
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
@@ -33,18 +34,25 @@
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import com.android.systemui.qs.QSAnimator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QuickQSPanel;
+import com.android.systemui.qs.TouchAnimator;
+import com.android.systemui.qs.TouchAnimator.Listener;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.tuner.TunerService;
public class QuickStatusBarHeader extends BaseStatusBarHeader implements
- NextAlarmController.NextAlarmChangeCallback, View.OnClickListener {
+ NextAlarmChangeCallback, OnClickListener, Listener {
private static final String TAG = "QuickStatusBarHeader";
+
+ private static final float EXPAND_INDICATOR_THRESHOLD = .93f;
+
private ActivityStarter mActivityStarter;
private NextAlarmController mNextAlarmController;
private SettingsButton mSettingsButton;
@@ -58,11 +66,12 @@
private boolean mExpanded;
private boolean mAlarmShowing;
- private ViewGroup mExpandedGroup;
private ViewGroup mDateTimeGroup;
private ViewGroup mDateTimeAlarmGroup;
private TextView mEmergencyOnly;
+ private ExpandableIndicator mExpandIndicator;
+
private boolean mListening;
private AlarmManager.AlarmClockInfo mNextAlarm;
@@ -73,8 +82,16 @@
private float mDateTimeTranslation;
private float mDateTimeAlarmTranslation;
- private float mExpansionFraction;
private float mDateScaleFactor;
+ private float mGearTranslation;
+
+ private TouchAnimator mAnimator;
+ private TouchAnimator mSecondHalfAnimator;
+ private TouchAnimator mFirstHalfAnimator;
+ private TouchAnimator mDateSizeAnimator;
+ private TouchAnimator mAlarmTranslation;
+ private TouchAnimator mSettingsAlpha;
+ private float mExpansionAmount;
public QuickStatusBarHeader(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -89,8 +106,10 @@
mDateTimeAlarmGroup = (ViewGroup) findViewById(R.id.date_time_alarm_group);
mDateTimeAlarmGroup.findViewById(R.id.empty_time_view).setVisibility(View.GONE);
mDateTimeGroup = (ViewGroup) findViewById(R.id.date_time_group);
+ mDateTimeGroup.setPivotX(0);
+ mDateTimeGroup.setPivotY(0);
- mExpandedGroup = (ViewGroup) findViewById(R.id.expanded_group);
+ mExpandIndicator = (ExpandableIndicator) findViewById(R.id.expand_indicator);
mHeaderQsPanel = (QuickQSPanel) findViewById(R.id.quick_qs_panel);
@@ -131,6 +150,8 @@
FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
FontSizeUtils.updateFontSize(mEmergencyOnly, R.dimen.qs_emergency_calls_only_text_size);
+ mGearTranslation = mContext.getResources().getDimension(R.dimen.qs_header_gear_translation);
+
mDateTimeTranslation = mContext.getResources().getDimension(
R.dimen.qs_date_anim_translation);
mDateTimeAlarmTranslation = mContext.getResources().getDimension(
@@ -139,8 +160,34 @@
R.dimen.qs_date_collapsed_text_size);
float dateExpandedSize = mContext.getResources().getDimension(
R.dimen.qs_date_text_size);
- mDateScaleFactor = dateExpandedSize / dateCollapsedSize - 1;
+ mDateScaleFactor = dateExpandedSize / dateCollapsedSize;
updateDateTimePosition();
+
+ mAnimator = new TouchAnimator.Builder()
+ .addFloat(mSettingsContainer, "translationY", -mGearTranslation, 0)
+ .addFloat(mMultiUserSwitch, "translationY", -mGearTranslation, 0)
+ .setListener(this)
+ .build();
+ mSecondHalfAnimator = new TouchAnimator.Builder()
+ .addFloat(mSettingsButton, "rotation", -180, 0)
+ .addFloat(mAlarmStatus, "alpha", 0, 1)
+ .addFloat(mEmergencyOnly, "alpha", 0, 1)
+ .setStartDelay(.5f)
+ .build();
+ mFirstHalfAnimator = new TouchAnimator.Builder()
+ .addFloat(mAlarmStatusCollapsed, "alpha", 1, 0)
+ .setEndDelay(.5f)
+ .build();
+ mDateSizeAnimator = new TouchAnimator.Builder()
+ .addFloat(mDateTimeGroup, "scaleX", 1, mDateScaleFactor)
+ .addFloat(mDateTimeGroup, "scaleY", 1, mDateScaleFactor)
+ .setStartDelay(.36f)
+ .build();
+ mSettingsAlpha = new TouchAnimator.Builder()
+ .addFloat(mSettingsContainer, "alpha", 0, 1)
+ .addFloat(mMultiUserSwitch, "alpha", 0, 1)
+ .setStartDelay(QSAnimator.EXPANDED_TILE_DELAY)
+ .build();
}
@Override
@@ -165,45 +212,53 @@
if (nextAlarm != null) {
mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
}
- mAlarmShowing = nextAlarm != null;
- updateEverything();
+ if (mAlarmShowing != (nextAlarm != null)) {
+ mAlarmShowing = nextAlarm != null;
+ updateEverything();
+ }
}
@Override
public void setExpansion(float headerExpansionFraction) {
- mExpansionFraction = headerExpansionFraction;
+ mExpansionAmount = headerExpansionFraction;
+ mAnimator.setPosition(headerExpansionFraction);
+ mSecondHalfAnimator.setPosition(headerExpansionFraction);
+ mFirstHalfAnimator.setPosition(headerExpansionFraction);
+ mDateSizeAnimator.setPosition(headerExpansionFraction);
+ mAlarmTranslation.setPosition(headerExpansionFraction);
+ mSettingsAlpha.setPosition(headerExpansionFraction);
- mExpandedGroup.setAlpha(headerExpansionFraction);
- mExpandedGroup.setVisibility(headerExpansionFraction > 0 ? View.VISIBLE : View.INVISIBLE);
-
- mHeaderQsPanel.setAlpha(1 - headerExpansionFraction);
- mHeaderQsPanel.setVisibility(headerExpansionFraction < 1 ? View.VISIBLE : View.INVISIBLE);
-
- mAlarmStatus.setAlpha(headerExpansionFraction);
- mAlarmStatusCollapsed.setAlpha(1 - headerExpansionFraction);
updateAlarmVisibilities();
- float textScale = headerExpansionFraction * mDateScaleFactor;
- mDateTimeGroup.setScaleX(1 + textScale);
- mDateTimeGroup.setScaleY(1 + textScale);
- mDateTimeGroup.setTranslationX(textScale * mDateTimeGroup.getWidth() / 2);
- mDateTimeGroup.setTranslationY(textScale * mDateTimeGroup.getHeight() / 2);
- updateDateTimePosition();
+ mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
+ }
- mEmergencyOnly.setAlpha(headerExpansionFraction);
+ @Override
+ public void onAnimationAtStart() {
+ }
+
+ @Override
+ public void onAnimationAtEnd() {
+ mHeaderQsPanel.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void onAnimationStarted() {
+ mHeaderQsPanel.setVisibility(View.VISIBLE);
}
private void updateAlarmVisibilities() {
- mAlarmStatus.setVisibility(mAlarmShowing && mExpansionFraction > 0
- ? View.VISIBLE : View.INVISIBLE);
- mAlarmStatusCollapsed.setVisibility(mAlarmShowing && mExpansionFraction < 1
- ? View.VISIBLE : View.INVISIBLE);
+ mAlarmStatus.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
+ mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
}
private void updateDateTimePosition() {
- float translation = mAlarmShowing ? mDateTimeAlarmTranslation
- : mDateTimeTranslation;
- mDateTimeAlarmGroup.setTranslationY(mExpansionFraction * translation);
+ // This one has its own because we have to rebuild it every time the alarm state changes.
+ mAlarmTranslation = new TouchAnimator.Builder()
+ .addFloat(mDateTimeAlarmGroup, "translationY", 0, mAlarmShowing
+ ? mDateTimeAlarmTranslation : mDateTimeTranslation)
+ .build();
+ mAlarmTranslation.setPosition(mExpansionAmount);
}
public void setListening(boolean listening) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
deleted file mode 100644
index d47050c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DisplayController.java
+++ /dev/null
@@ -1,193 +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.systemui.statusbar.policy;
-
-import libcore.util.Objects;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.provider.Settings;
-
-import com.android.systemui.R;
-import com.android.systemui.tuner.TunerService;
-
-import java.util.ArrayList;
-
-public class DisplayController implements TunerService.Tunable {
-
- public static final String COLOR_MATRIX_CUSTOM_ENABLED = "tuner_color_custom_enabled";
- public static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
-
- public static final String COLOR_STATE = "sysui_color_matrix_state";
-
- public static final int COLOR_STATE_DISABLED = 0;
- public static final int COLOR_STATE_ENABLED = 1;
- public static final int COLOR_STATE_AUTO = 2;
-
- public static final String AUTO_STRING = "auto_mode";
- public static final String NONE_STRING = "none";
-
- public static final int AUTO_INDEX = 2;
- public static final int CUSTOM_INDEX = 3;
-
- // Night mode ~= 3400 K
- private static final float[] NIGHT_VALUES = new float[] {
- 1, 0, 0, 0,
- 0, .754f, 0, 0,
- 0, 0, .516f, 0,
- 0, 0, 0, 1,
- };
- public static final float[] IDENTITY_MATRIX = new float[] {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1,
- };
-
- private final ArrayList<Listener> mListeners = new ArrayList<>();
-
- private final Context mContext;
-
- private String mCurrentValue;
- private boolean mListening;
-
- public DisplayController(Context context) {
- mContext = context;
- TunerService.get(mContext).addTunable(this, COLOR_STATE,
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
- }
-
- public void addListener(Listener listener) {
- mListeners.add(listener);
- listener.onCurrentMatrixChanged();
- }
-
- public void removeListener(Listener listener) {
- mListeners.remove(listener);
- }
-
- public boolean isEnabled() {
- return TunerService.get(mContext).getValue(COLOR_STATE, COLOR_STATE_DISABLED)
- != COLOR_STATE_DISABLED;
- }
-
- public boolean isAuto() {
- return mListening;
- }
-
- public void setAuto(boolean auto) {
- TunerService.get(mContext).setValue(COLOR_STATE, auto ? COLOR_STATE_AUTO
- : COLOR_STATE_DISABLED);
- }
-
- public boolean isCustomSet() {
- return isCustomEnabled() && Objects.equal(getCurrentMatrix(), getCustomValues());
- }
-
- public String getCurrentMatrix() {
- return mCurrentValue;
- }
-
- public String getCustomValues() {
- return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_VALUES);
- }
-
- public boolean isCustomEnabled() {
- return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_ENABLED, 0) != 0;
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX.equals(key)) {
- mCurrentValue = newValue;
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onCurrentMatrixChanged();
- }
- } else if (COLOR_STATE.equals(key)) {
- final boolean listening = newValue != null
- && Integer.parseInt(newValue) == COLOR_STATE_AUTO;
- if (listening && !mListening) {
- mListening = true;
- mContext.registerReceiver(mReceiver,
- new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
- updateNightMode();
- } else if (!listening && mListening) {
- mListening = false;
- mContext.unregisterReceiver(mReceiver);
- }
- for (int i = 0; i < mListeners.size(); i++) {
- mListeners.get(i).onCurrentMatrixChanged();
- }
- }
- }
-
- private void updateNightMode() {
- final int uiMode = mContext.getResources().getConfiguration().uiMode;
- final boolean isNightMode = (uiMode & Configuration.UI_MODE_NIGHT_MASK)
- == Configuration.UI_MODE_NIGHT_YES;
- String value = null;
- if (isNightMode) {
- value = toString(NIGHT_VALUES);
- }
- TunerService.get(mContext).setValue(Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
- value);
- }
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
- updateNightMode();
- }
- }
- };
-
- public interface Listener {
- void onCurrentMatrixChanged();
- }
-
- public static String[] getColorTransforms(Context context) {
- return new String[] {
- NONE_STRING,
- toString(NIGHT_VALUES),
- AUTO_STRING, // Blank spot for auto values
- null, // Blank spot for custom values
- };
- }
-
- public static CharSequence[] getColorTitles(Context context) {
- // TODO: Move to string array resource.
- return new CharSequence[]{
- context.getString(R.string.color_matrix_none),
- context.getString(R.string.color_matrix_night),
- context.getString(R.string.color_matrix_auto),
- context.getString(R.string.color_matrix_custom),
- };
- }
-
- public static String toString(float[] values) {
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < values.length; i++) {
- if (builder.length() != 0) {
- builder.append(',');
- }
- builder.append(values[i]);
- }
- return builder.toString();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 500d603..047f14d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -21,7 +21,6 @@
void removeCallback(Callback callback);
boolean isHotspotEnabled();
void setHotspotEnabled(boolean enabled);
- boolean isTetheringAllowed();
public interface Callback {
void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 07b7409..f03d9e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,15 +16,12 @@
package com.android.systemui.statusbar.policy;
-import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.util.Log;
import java.io.FileDescriptor;
@@ -40,8 +37,6 @@
private final Receiver mReceiver = new Receiver();
private final ConnectivityManager mConnectivityManager;
private final Context mContext;
- private final UserManager mUserManager;
- private final int mCurrentUser;
private int mHotspotState;
@@ -49,8 +44,6 @@
mContext = context;
mConnectivityManager = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- mCurrentUser = ActivityManager.getCurrentUser();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -95,12 +88,6 @@
return mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED;
}
- @Override
- public boolean isTetheringAllowed() {
- return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING,
- UserHandle.of(mCurrentUser));
- }
-
static final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 401943e..29a8981 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -21,7 +21,6 @@
boolean setLocationEnabled(boolean enabled);
void addSettingsChangedCallback(LocationSettingsChangeCallback cb);
void removeSettingsChangedCallback(LocationSettingsChangeCallback cb);
- boolean isUserLocationRestricted();
/**
* A callback for change in location settings (the user has enabled/disabled location).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 436a40d..8d84be4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -52,7 +52,6 @@
private AppOpsManager mAppOpsManager;
private StatusBarManager mStatusBarManager;
- private final int mCurrentUser;
private boolean mAreActiveLocationRequests;
@@ -74,7 +73,6 @@
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mStatusBarManager
= (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
- mCurrentUser = ActivityManager.getCurrentUser();
// Examine the current location state and initialize the status view.
updateActiveLocationRequests();
@@ -105,6 +103,10 @@
* @return true if attempt to change setting was successful.
*/
public boolean setLocationEnabled(boolean enabled) {
+ int currentUserId = ActivityManager.getCurrentUser();
+ if (isUserLocationRestricted(currentUserId)) {
+ return false;
+ }
final ContentResolver cr = mContext.getContentResolver();
// When enabling location, a user consent dialog will pop up, and the
// setting won't be fully enabled until the user accepts the agreement.
@@ -113,7 +115,7 @@
// QuickSettings always runs as the owner, so specifically set the settings
// for the current foreground user.
return Settings.Secure
- .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, mCurrentUser);
+ .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId);
}
/**
@@ -131,10 +133,10 @@
/**
* Returns true if the current user is restricted from using location.
*/
- public boolean isUserLocationRestricted() {
+ private boolean isUserLocationRestricted(int userId) {
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
return um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
- UserHandle.of(mCurrentUser));
+ UserHandle.of(userId));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java
new file mode 100644
index 0000000..0b1911b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import libcore.util.Objects;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.opengl.Matrix;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.util.MathUtils;
+
+import com.android.systemui.tuner.TunerService;
+
+import java.util.ArrayList;
+
+/**
+ * Listens for changes to twilight from the TwilightService.
+ *
+ * Also pushes the current matrix to accessibility based on the current twilight
+ * and various tuner settings.
+ */
+public class NightModeController implements TunerService.Tunable {
+
+ public static final String NIGHT_MODE_ADJUST_TINT = "tuner_night_mode_adjust_tint";
+ private static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
+
+ private static final String ACTION_TWILIGHT_CHANGED = "android.intent.action.TWILIGHT_CHANGED";
+
+ private static final String EXTRA_IS_NIGHT = "isNight";
+ private static final String EXTRA_AMOUNT = "amount";
+
+ // Night mode ~= 3400 K
+ private static final float[] NIGHT_VALUES = new float[] {
+ 1, 0, 0, 0,
+ 0, .754f, 0, 0,
+ 0, 0, .516f, 0,
+ 0, 0, 0, 1,
+ };
+ public static final float[] IDENTITY_MATRIX = new float[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1,
+ };
+
+ private final ArrayList<Listener> mListeners = new ArrayList<>();
+
+ private final Context mContext;
+
+ // This is whether or not this is the main NightMode controller in SysUI that should be
+ // updating relevant color matrixes or if its in the tuner process getting current state
+ // for UI.
+ private final boolean mUpdateMatrix;
+
+ private float[] mCustomMatrix;
+ private boolean mListening;
+ private boolean mAdjustTint;
+
+ private boolean mIsNight;
+ private float mAmount;
+ private boolean mIsAuto;
+
+ public NightModeController(Context context) {
+ this(context, false);
+ }
+
+ public NightModeController(Context context, boolean updateMatrix) {
+ mContext = context;
+ mUpdateMatrix = updateMatrix;
+ TunerService.get(mContext).addTunable(this, NIGHT_MODE_ADJUST_TINT,
+ COLOR_MATRIX_CUSTOM_VALUES, Secure.TWILIGHT_MODE);
+ }
+
+ public void setNightMode(boolean isNight) {
+ if (mIsAuto) {
+ if (mIsNight != isNight) {
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, isNight
+ ? Secure.TWILIGHT_MODE_AUTO_OVERRIDE_ON
+ : Secure.TWILIGHT_MODE_AUTO_OVERRIDE_OFF);
+ } else {
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE,
+ Secure.TWILIGHT_MODE_AUTO);
+ }
+ } else {
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, isNight
+ ? Secure.TWILIGHT_MODE_LOCKED_ON : Secure.TWILIGHT_MODE_LOCKED_OFF);
+ }
+ }
+
+ public void setAuto(boolean auto) {
+ mIsAuto = auto;
+ if (auto) {
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, Secure.TWILIGHT_MODE_AUTO);
+ } else {
+ // Lock into the current state
+ TunerService.get(mContext).setValue(Secure.TWILIGHT_MODE, mIsNight
+ ? Secure.TWILIGHT_MODE_LOCKED_ON : Secure.TWILIGHT_MODE_LOCKED_OFF);
+ }
+ }
+
+ public boolean isAuto() {
+ return mIsAuto;
+ }
+
+ public void setAdjustTint(Boolean newValue) {
+ TunerService.get(mContext).setValue(NIGHT_MODE_ADJUST_TINT, ((Boolean) newValue) ? 1 : 0);
+ }
+
+ public void addListener(Listener listener) {
+ mListeners.add(listener);
+ listener.onNightModeChanged();
+ updateListening();
+ }
+
+ public void removeListener(Listener listener) {
+ mListeners.remove(listener);
+ updateListening();
+ }
+
+ private void updateListening() {
+ boolean shouldListen = mListeners.size() != 0 || (mUpdateMatrix && mAdjustTint);
+ if (shouldListen == mListening) return;
+ mListening = shouldListen;
+ if (mListening) {
+ mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_TWILIGHT_CHANGED));
+ } else {
+ mContext.unregisterReceiver(mReceiver);
+ }
+ }
+
+ public boolean isEnabled() {
+ if (!mListening) {
+ updateNightMode(mContext.registerReceiver(null,
+ new IntentFilter(ACTION_TWILIGHT_CHANGED)));
+ }
+ return mIsNight;
+ }
+
+ public String getCustomValues() {
+ return TunerService.get(mContext).getValue(COLOR_MATRIX_CUSTOM_VALUES);
+ }
+
+ public void setCustomValues(String values) {
+ TunerService.get(mContext).setValue(COLOR_MATRIX_CUSTOM_VALUES, values);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
+ mCustomMatrix = newValue != null ? toValues(newValue) : null;
+ updateCurrentMatrix();
+ } else if (NIGHT_MODE_ADJUST_TINT.equals(key)) {
+ mAdjustTint = newValue == null || Integer.parseInt(newValue) != 0;
+ updateListening();
+ updateCurrentMatrix();
+ } else if (Secure.TWILIGHT_MODE.equals(key)) {
+ mIsAuto = newValue != null && Integer.parseInt(newValue) >= Secure.TWILIGHT_MODE_AUTO;
+ }
+ }
+
+ private void updateCurrentMatrix() {
+ if (!mUpdateMatrix) return;
+ if ((!mAdjustTint || mAmount == 0) && mCustomMatrix == null) {
+ TunerService.get(mContext).setValue(Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+ return;
+ }
+ float[] values = scaleValues(IDENTITY_MATRIX, NIGHT_VALUES, mAdjustTint ? mAmount : 0);
+ if (mCustomMatrix != null) {
+ values = multiply(values, mCustomMatrix);
+ }
+ TunerService.get(mContext).setValue(Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+ toString(values));
+ }
+
+ private void updateNightMode(Intent intent) {
+ mIsNight = intent.getBooleanExtra(EXTRA_IS_NIGHT, false);
+ mAmount = intent.getFloatExtra(EXTRA_AMOUNT, 0);
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_TWILIGHT_CHANGED.equals(intent.getAction())) {
+ updateNightMode(intent);
+ updateCurrentMatrix();
+ for (int i = 0; i < mListeners.size(); i++) {
+ mListeners.get(i).onNightModeChanged();
+ }
+ }
+ }
+ };
+
+ public interface Listener {
+ void onNightModeChanged();
+ void onTwilightAutoChanged();
+ }
+
+ private static float[] multiply(float[] matrix, float[] other) {
+ if (matrix == null) {
+ return other;
+ }
+ float[] result = new float[16];
+ Matrix.multiplyMM(result, 0, matrix, 0, other, 0);
+ return result;
+ }
+
+ private float[] scaleValues(float[] identityMatrix, float[] nightValues, float amount) {
+ float[] values = new float[identityMatrix.length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = MathUtils.lerp(identityMatrix[i], nightValues[i], amount);
+ }
+ return values;
+ }
+
+ public static String toString(float[] values) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < values.length; i++) {
+ if (builder.length() != 0) {
+ builder.append(',');
+ }
+ builder.append(values[i]);
+ }
+ return builder.toString();
+ }
+
+ public static float[] toValues(String customValues) {
+ String[] strValues = customValues.split(",");
+ float[] values = new float[strValues.length];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = Float.parseFloat(strValues[i]);
+ }
+ return values;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 6ca7dc8..13369f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -210,12 +210,16 @@
}
}
+ boolean systemCanCreateUsers = !mUserManager.hasBaseUserRestriction(
+ UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM);
boolean currentUserCanCreateUsers = currentUserInfo != null
&& (currentUserInfo.isAdmin()
- || currentUserInfo.id == UserHandle.USER_SYSTEM);
- boolean canCreateGuest = (currentUserCanCreateUsers || addUsersWhenLocked)
+ || currentUserInfo.id == UserHandle.USER_SYSTEM)
+ && systemCanCreateUsers;
+ boolean anyoneCanCreateUsers = systemCanCreateUsers && addUsersWhenLocked;
+ boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
&& guestRecord == null;
- boolean canCreateUser = (currentUserCanCreateUsers || addUsersWhenLocked)
+ boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
&& mUserManager.canAddMoreUsers();
boolean createIsRestricted = !addUsersWhenLocked;
@@ -225,7 +229,7 @@
guestRecord = new UserRecord(null /* info */, null /* picture */,
true /* isGuest */, false /* isCurrent */,
false /* isAddUser */, createIsRestricted);
- checkIfAddUserDisallowed(guestRecord);
+ checkIfAddUserDisallowedByAdminOnly(guestRecord);
records.add(guestRecord);
}
} else {
@@ -238,7 +242,7 @@
UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
createIsRestricted);
- checkIfAddUserDisallowed(addUserRecord);
+ checkIfAddUserDisallowedByAdminOnly(addUserRecord);
records.add(addUserRecord);
}
@@ -615,10 +619,11 @@
}
}
- private void checkIfAddUserDisallowed(UserRecord record) {
+ private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser());
- if (admin != null) {
+ if (admin != null && !RestrictedLockUtils.hasBaseUserRestriction(mContext,
+ UserManager.DISALLOW_ADD_USER, ActivityManager.getCurrentUser())) {
record.isDisabledByAdmin = true;
record.enforcedAdmin = admin;
} else {
@@ -683,7 +688,7 @@
}
public final QSTile.DetailAdapter userDetailAdapter = new QSTile.DetailAdapter() {
- private final Intent USER_SETTINGS_INTENT = new Intent("android.settings.USER_SETTINGS");
+ private final Intent USER_SETTINGS_INTENT = new Intent(Settings.ACTION_USER_SETTINGS);
@Override
public CharSequence getTitle() {
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 bf4245b..f078b53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -18,10 +18,12 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
@@ -32,6 +34,7 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
@@ -56,6 +59,8 @@
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationOverflowContainer;
+import com.android.systemui.statusbar.NotificationSettingsIconRow;
+import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -72,7 +77,8 @@
*/
public class NotificationStackScrollLayout extends ViewGroup
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
- ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener {
+ ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
+ SettingsIconRowListener {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -207,6 +213,11 @@
*/
private int mMaxScrollAfterExpand;
private SwipeHelper.LongPressListener mLongPressListener;
+ private GearDisplayedListener mGearDisplayedListener;
+
+ private NotificationSettingsIconRow mCurrIconRow;
+ private View mTranslatingParentView;
+ private View mGearExposedView;
/**
* Should in this touch motion only be scrolling allowed? It's true when the scroller was
@@ -304,8 +315,7 @@
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(this);
-
- mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
+ mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, this, getContext());
mSwipeHelper.setLongPressListener(mLongPressListener);
mStackScrollAlgorithm = new StackScrollAlgorithm(context);
initView(context);
@@ -321,6 +331,13 @@
}
@Override
+ public void onGearTouched(ExpandableNotificationRow row) {
+ if (mLongPressListener != null) {
+ mLongPressListener.onLongPress(row, 0, 0);
+ }
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(0, mCurrentBounds.top, getWidth(), mCurrentBounds.bottom, mBackgroundPaint);
if (DEBUG) {
@@ -630,6 +647,10 @@
mLongPressListener = listener;
}
+ public void setGearDisplayedListener(GearDisplayedListener listener) {
+ mGearDisplayedListener = listener;
+ }
+
public void setQsContainer(ViewGroup qsContainer) {
mQsContainer = qsContainer;
}
@@ -666,7 +687,7 @@
}
@Override
- public void onChildSnappedBack(View animView) {
+ public void onChildSnappedBack(View animView, float targetLeft) {
mAmbientState.onDragFinished(animView);
if (!mDragAnimPendingChildren.contains(animView)) {
if (mAnimationsEnabled) {
@@ -678,6 +699,13 @@
// We start the swipe and snap back in the same frame, we don't want any animation
mDragAnimPendingChildren.remove(animView);
}
+
+ if (targetLeft == 0 && mCurrIconRow != null) {
+ mCurrIconRow.resetState();
+ if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
+ mGearExposedView = null;
+ }
+ }
}
@Override
@@ -686,7 +714,7 @@
mScrimController.setTopHeadsUpDragAmount(animView,
Math.min(Math.abs(swipeProgress - 1.0f), 1.0f));
}
- return false;
+ return true; // Don't fade out the notification
}
public void onBeginDrag(View v) {
@@ -726,8 +754,21 @@
return mPhoneStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
}
+ @Override
public View getChildAtPosition(MotionEvent ev) {
- return getChildAtPosition(ev.getX(), ev.getY());
+ View child = getChildAtPosition(ev.getX(), ev.getY());
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ ExpandableNotificationRow parent = row.getNotificationParent();
+ if (mGearExposedView != null && parent != null
+ && parent.areChildrenExpanded() && mGearExposedView == parent) {
+ // In this case the group is expanded and showing the gear for the
+ // group, further interaction should apply to the group, not any
+ // child notifications so we use the parent of the child.
+ child = row.getNotificationParent();
+ }
+ }
+ return child;
}
public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {
@@ -841,10 +882,6 @@
return mScrollingEnabled;
}
- public View getChildContentView(View v) {
- return v;
- }
-
public boolean canChildBeDismissed(View v) {
return StackScrollAlgorithm.canChildBeDismissed(v);
}
@@ -3008,6 +3045,9 @@
disableClipOptimization();
}
handleDismissAllClipping();
+ if (mCurrIconRow != null & mCurrIconRow.isVisible()) {
+ mCurrIconRow.getNotificationParent().animateTranslateNotification(0 /* left target */);
+ }
}
private void handleDismissAllClipping() {
@@ -3268,6 +3308,247 @@
public void flingTopOverscroll(float velocity, boolean open);
}
+ /**
+ * A listener that is notified when the gear is shown behind a notification.
+ */
+ public interface GearDisplayedListener {
+ void onGearDisplayed(ExpandableNotificationRow row);
+ }
+
+ private class NotificationSwipeHelper extends SwipeHelper {
+ private static final int MOVE_STATE_LEFT = -1;
+ private static final int MOVE_STATE_UNDEFINED = 0;
+ private static final int MOVE_STATE_RIGHT = 1;
+
+ private static final long GEAR_SHOW_DELAY = 60;
+
+ private ArrayList<View> mTranslatingViews = new ArrayList<>();
+ private CheckForDrag mCheckForDrag;
+ private Handler mHandler;
+ private int mMoveState = MOVE_STATE_UNDEFINED;
+
+ public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
+ super(swipeDirection, callback, context);
+ mHandler = new Handler();
+ }
+
+ @Override
+ public void onDownUpdate(View currView) {
+ // Set the active view
+ mTranslatingParentView = currView;
+
+ // Reset check for drag gesture
+ mCheckForDrag = null;
+
+ // Slide back any notifications that might be showing a gear
+ resetExposedGearView();
+
+ if (currView instanceof ExpandableNotificationRow) {
+ // Set the listener for the current row's gear
+ mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
+ mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
+
+ // And the translating children
+ mTranslatingViews = ((ExpandableNotificationRow) currView).getContentViews();
+ }
+ mMoveState = MOVE_STATE_UNDEFINED;
+ }
+
+ @Override
+ public void onMoveUpdate(View view, float translation, float delta) {
+ final int newMoveState = (delta < 0) ? MOVE_STATE_RIGHT : MOVE_STATE_LEFT;
+ if (mMoveState != MOVE_STATE_UNDEFINED && mMoveState != newMoveState) {
+ // Changed directions, make sure we check for drag again.
+ mCheckForDrag = null;
+ }
+ mMoveState = newMoveState;
+
+ if (view instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) view).setTranslationForOutline(translation);
+ if (!isPinnedHeadsUp(view)) {
+ // Only show the gear if we're not a heads up view.
+ checkForDrag();
+ if (mCurrIconRow != null) {
+ mCurrIconRow.updateSettingsIcons(translation, getSize(view));
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dismissChild(final View view, float velocity) {
+ cancelCheckForDrag();
+ super.dismissChild(view, velocity);
+ }
+
+ @Override
+ public void snapChild(final View animView, final float targetLeft, float velocity) {
+ final float snapBackThreshold = getSpaceForGear(animView);
+ final float translation = getTranslation(animView);
+ final boolean fromLeft = translation > 0;
+ final float absTrans = Math.abs(translation);
+ final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
+
+ boolean pastGear = (fromLeft && translation >= snapBackThreshold * 0.4f
+ && translation <= notiThreshold) ||
+ (!fromLeft && absTrans >= snapBackThreshold * 0.4f
+ && absTrans <= notiThreshold);
+
+ if (pastGear && !isPinnedHeadsUp(animView)) {
+ // bouncity
+ final float target = fromLeft ? snapBackThreshold : -snapBackThreshold;
+ mGearExposedView = mTranslatingParentView;
+ if (mGearDisplayedListener != null
+ && (animView instanceof ExpandableNotificationRow)) {
+ mGearDisplayedListener.onGearDisplayed((ExpandableNotificationRow) animView);
+ }
+ super.snapChild(animView, target, velocity);
+ } else {
+ super.snapChild(animView, 0, velocity);
+ }
+ }
+
+ @Override
+ public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
+ if (mDismissAllInProgress) {
+ // When dismissing all, we translate the entire view instead.
+ super.onTranslationUpdate(animView, value, canBeDismissed);
+ return;
+ }
+ if (animView instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) animView).setTranslationForOutline(value);
+ }
+ if (mCurrIconRow != null) {
+ mCurrIconRow.updateSettingsIcons(value, getSize(animView));
+ }
+ }
+
+ @Override
+ public Animator getViewTranslationAnimator(View v, float target,
+ AnimatorUpdateListener listener) {
+ if (mDismissAllInProgress) {
+ // When dismissing all, we translate the entire view instead.
+ return super.getViewTranslationAnimator(v, target, listener);
+ }
+ ArrayList<Animator> animators = new ArrayList<Animator>();
+ for (int i = 0; i < mTranslatingViews.size(); i++) {
+ ObjectAnimator anim = createTranslationAnimation(mTranslatingViews.get(i), target);
+ animators.add(anim);
+ if (i == 0 && listener != null) {
+ anim.addUpdateListener(listener);
+ }
+ }
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(animators);
+ return set;
+ }
+
+ @Override
+ public void setTranslation(View v, float translate) {
+ if (mDismissAllInProgress) {
+ // When dismissing all, we translate the entire view instead.
+ super.setTranslation(v, translate);
+ return;
+ }
+ // Translate the group of views
+ for (int i = 0; i < mTranslatingViews.size(); i++) {
+ if (mTranslatingViews.get(i) != null) {
+ super.setTranslation(mTranslatingViews.get(i), translate);
+ }
+ }
+ }
+
+ @Override
+ public float getTranslation(View v) {
+ if (mDismissAllInProgress) {
+ // When dismissing all, we translate the entire view instead.
+ return super.getTranslation(v);
+ }
+ // All of the views in the list should have same translation, just use first one.
+ if (mTranslatingViews.size() > 0) {
+ return super.getTranslation(mTranslatingViews.get(0));
+ }
+ return 0;
+ }
+
+
+ /**
+ * Returns the horizontal space in pixels required to display the gear behind a
+ * notification.
+ */
+ private float getSpaceForGear(View view) {
+ if (view instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) view).getSpaceForGear();
+ }
+ return 0;
+ }
+
+ private void checkForDrag() {
+ if (mCheckForDrag == null) {
+ mCheckForDrag = new CheckForDrag();
+ mHandler.postDelayed(mCheckForDrag, GEAR_SHOW_DELAY);
+ }
+ }
+
+ private void cancelCheckForDrag() {
+ if (mCurrIconRow != null) {
+ mCurrIconRow.cancelFadeAnimator();
+ }
+ mHandler.removeCallbacks(mCheckForDrag);
+ mCheckForDrag = null;
+ }
+
+ private final class CheckForDrag implements Runnable {
+ @Override
+ public void run() {
+ final float translation = getTranslation(mTranslatingParentView);
+ final float absTransX = Math.abs(translation);
+ final float bounceBackToGearWidth = getSpaceForGear(mTranslatingParentView);
+ final float notiThreshold = getSize(mTranslatingParentView) * 0.4f;
+ if (mCurrIconRow != null && absTransX >= bounceBackToGearWidth * 0.4
+ && absTransX < notiThreshold) {
+ // Show icon
+ mCurrIconRow.fadeInSettings(translation > 0 /* fromLeft */, translation,
+ notiThreshold);
+ } else {
+ // Allow more to be posted if this wasn't a drag.
+ mCheckForDrag = null;
+ }
+ }
+ }
+
+ private void resetExposedGearView() {
+ if (mGearExposedView == null || mGearExposedView == mTranslatingParentView) {
+ // If no gear is showing or it's showing for this view we do nothing.
+ return;
+ }
+
+ final View prevGearExposedView = mGearExposedView;
+ mGearExposedView = null;
+
+ AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animator) {
+ if (prevGearExposedView instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) prevGearExposedView).getSettingsRow()
+ .resetState();
+ }
+ }
+ };
+ AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ if (prevGearExposedView instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) prevGearExposedView)
+ .setTranslationForOutline((float) animation.getAnimatedValue());
+ }
+ }
+ };
+ Animator set = getViewTranslationAnimator(prevGearExposedView, 0, updateListener);
+ set.addListener(listener);
+ set.start();
+ }
+ }
+
static class AnimationEvent {
static AnimationFilter[] FILTERS = new AnimationFilter[] {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
new file mode 100644
index 0000000..8881c79
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v7.preference.DropDownPreference;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+
+import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
+
+public class BatteryPreference extends DropDownPreference implements TunerService.Tunable {
+
+ private static final String PERCENT = "percent";
+ private static final String DEFAULT = "default";
+ private static final String DISABLED = "disabled";
+
+ private final String mBattery;
+ private boolean mBatteryEnabled;
+ private boolean mHasPercentage;
+ private ArraySet<String> mBlacklist;
+ private boolean mHasSetValue;
+
+ public BatteryPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mBattery = context.getString(com.android.internal.R.string.status_bar_battery);
+ setEntryValues(new CharSequence[] {PERCENT, DEFAULT, DISABLED });
+ }
+
+ @Override
+ public void onAttached() {
+ super.onAttached();
+ TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ mHasPercentage = Settings.System.getInt(getContext().getContentResolver(),
+ SHOW_PERCENT_SETTING, 0) != 0;
+ }
+
+ @Override
+ public void onDetached() {
+ TunerService.get(getContext()).removeTunable(this);
+ super.onDetached();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ mBlacklist = StatusBarIconController.getIconBlacklist(newValue);
+ mBatteryEnabled = !mBlacklist.contains(mBattery);
+ }
+ if (!mHasSetValue) {
+ // Because of the complicated tri-state it can end up looping and setting state back to
+ // what the user didn't choose. To avoid this, just set the state once and rely on the
+ // preference to handle updates.
+ mHasSetValue = true;
+ if (mBatteryEnabled && mHasPercentage) {
+ setValue(PERCENT);
+ } else if (mBatteryEnabled) {
+ setValue(DEFAULT);
+ } else {
+ setValue(DISABLED);
+ }
+ }
+ }
+
+ @Override
+ protected boolean persistString(String value) {
+ final boolean v = PERCENT.equals(value);
+ MetricsLogger.action(getContext(), MetricsEvent.TUNER_BATTERY_PERCENTAGE, v);
+ Settings.System.putInt(getContext().getContentResolver(), SHOW_PERCENT_SETTING, v ? 1 : 0);
+ if (DISABLED.equals(value)) {
+ mBlacklist.add(mBattery);
+ } else {
+ mBlacklist.remove(mBattery);
+ }
+ TunerService.get(getContext()).setValue(StatusBarIconController.ICON_BLACKLIST,
+ TextUtils.join(",", mBlacklist));
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/CalibratePreference.java b/packages/SystemUI/src/com/android/systemui/tuner/CalibratePreference.java
new file mode 100644
index 0000000..ff7be13
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/CalibratePreference.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.content.Context;
+import android.support.v7.preference.DialogPreference;
+import android.util.AttributeSet;
+
+public class CalibratePreference extends DialogPreference {
+ public CalibratePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
new file mode 100644
index 0000000..ea92443
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.systemui.tuner;
+
+import android.content.Context;
+import android.support.v7.preference.DropDownPreference;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.Clock;
+
+public class ClockPreference extends DropDownPreference implements TunerService.Tunable {
+
+ private static final String SECONDS = "seconds";
+ private static final String DEFAULT = "default";
+ private static final String DISABLED = "disabled";
+
+ private final String mClock;
+ private boolean mClockEnabled;
+ private boolean mHasSeconds;
+ private ArraySet<String> mBlacklist;
+ private boolean mHasSetValue;
+
+ public ClockPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mClock = context.getString(com.android.internal.R.string.status_bar_clock);
+ setEntryValues(new CharSequence[] { SECONDS, DEFAULT, DISABLED });
+ }
+
+ @Override
+ public void onAttached() {
+ super.onAttached();
+ TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST,
+ Clock.CLOCK_SECONDS);
+ }
+
+ @Override
+ public void onDetached() {
+ TunerService.get(getContext()).removeTunable(this);
+ super.onDetached();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ mBlacklist = StatusBarIconController.getIconBlacklist(newValue);
+ mClockEnabled = !mBlacklist.contains(mClock);
+ } else if (Clock.CLOCK_SECONDS.equals(key)) {
+ mHasSeconds = newValue != null && Integer.parseInt(newValue) != 0;
+ }
+ if (!mHasSetValue) {
+ // Because of the complicated tri-state it can end up looping and setting state back to
+ // what the user didn't choose. To avoid this, just set the state once and rely on the
+ // preference to handle updates.
+ mHasSetValue = true;
+ if (mClockEnabled && mHasSeconds) {
+ setValue(SECONDS);
+ } else if (mClockEnabled) {
+ setValue(DEFAULT);
+ } else {
+ setValue(DISABLED);
+ }
+ }
+ }
+
+ @Override
+ protected boolean persistString(String value) {
+ TunerService.get(getContext()).setValue(Clock.CLOCK_SECONDS, SECONDS.equals(value) ? 1 : 0);
+ if (DISABLED.equals(value)) {
+ mBlacklist.add(mClock);
+ } else {
+ mBlacklist.remove(mClock);
+ }
+ TunerService.get(getContext()).setValue(StatusBarIconController.ICON_BLACKLIST,
+ TextUtils.join(",", mBlacklist));
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java
new file mode 100644
index 0000000..9f11325
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorAndAppearanceFragment.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.SeekBar;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NightModeController;
+
+public class ColorAndAppearanceFragment extends PreferenceFragment {
+
+ private static final String KEY_CALIBRATE = "calibrate";
+
+ private static final long RESET_DELAY = 10000;
+ private static final CharSequence KEY_NIGHT_MODE = "night_mode";
+
+ private NightModeController mNightModeController;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNightModeController = new NightModeController(getContext());
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.color_and_appearance);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // TODO: Figure out better title model for Tuner, to avoid any more of this.
+ getActivity().setTitle(R.string.color_and_appearance);
+
+ Preference nightMode = findPreference(KEY_NIGHT_MODE);
+ nightMode.setSummary(mNightModeController.isEnabled()
+ ? R.string.night_mode_on : R.string.night_mode_off);
+ }
+
+ @Override
+ public void onDisplayPreferenceDialog(Preference preference) {
+ if (preference instanceof CalibratePreference) {
+ CalibrateDialog.show(this);
+ } else {
+ super.onDisplayPreferenceDialog(preference);
+ }
+ }
+
+ private void startRevertTimer() {
+ getView().postDelayed(mResetColorMatrix, RESET_DELAY);
+ }
+
+ private void onApply() {
+ mNightModeController.setCustomValues(Settings.Secure.getString(
+ getContext().getContentResolver(), Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX));
+ getView().removeCallbacks(mResetColorMatrix);
+ }
+
+ private void onRevert() {
+ getView().removeCallbacks(mResetColorMatrix);
+ mResetColorMatrix.run();
+ }
+
+ private final Runnable mResetColorMatrix = new Runnable() {
+ @Override
+ public void run() {
+ ((DialogFragment) getFragmentManager().findFragmentByTag("RevertWarning")).dismiss();
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+ }
+ };
+
+ public static class CalibrateDialog extends DialogFragment implements
+ DialogInterface.OnClickListener {
+ private float[] mValues;
+ private NightModeController mNightModeController;
+
+ public static void show(ColorAndAppearanceFragment fragment) {
+ CalibrateDialog dialog = new CalibrateDialog();
+ dialog.setTargetFragment(fragment, 0);
+ dialog.show(fragment.getFragmentManager(), "Calibrate");
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNightModeController = new NightModeController(getContext());
+ String customValues = mNightModeController.getCustomValues();
+ if (customValues == null) {
+ // Generate this as a string because its the easiest way to generate a copy of the
+ // identity.
+ customValues = NightModeController.toString(NightModeController.IDENTITY_MATRIX);
+ }
+ mValues = NightModeController.toValues(customValues);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ View v = LayoutInflater.from(getContext()).inflate(R.layout.calibrate_sliders, null);
+ bindView(v.findViewById(R.id.r_group), 0);
+ bindView(v.findViewById(R.id.g_group), 5);
+ bindView(v.findViewById(R.id.b_group), 10);
+ return new AlertDialog.Builder(getContext())
+ .setTitle(R.string.calibrate_display)
+ .setView(v)
+ .setPositiveButton(R.string.color_apply, this)
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ }
+
+ private void bindView(View view, final int index) {
+ SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+ seekBar.setMax(1000);
+ seekBar.setProgress((int) (1000 * mValues[index]));
+ seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ mValues[index] = progress / 1000f;
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (mValues[0] == 1 && mValues[5] == 1 && mValues[10] == 1) {
+ // Allow removal of matrix by all values set to highest.
+ mNightModeController.setCustomValues(null);
+ return;
+ }
+ ((ColorAndAppearanceFragment) getTargetFragment()).startRevertTimer();
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+ NightModeController.toString(mValues));
+ RevertWarning.show((ColorAndAppearanceFragment) getTargetFragment());
+ }
+ }
+
+ public static class RevertWarning extends DialogFragment
+ implements DialogInterface.OnClickListener {
+
+ public static void show(ColorAndAppearanceFragment fragment) {
+ RevertWarning warning = new RevertWarning();
+ warning.setTargetFragment(fragment, 0);
+ warning.show(fragment.getFragmentManager(), "RevertWarning");
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog alertDialog = new AlertDialog.Builder(getContext())
+ .setTitle(R.string.color_revert_title)
+ .setMessage(R.string.color_revert_message)
+ .setPositiveButton(R.string.ok, this)
+ .create();
+ alertDialog.setCanceledOnTouchOutside(true);
+ return alertDialog;
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ ((ColorAndAppearanceFragment) getTargetFragment()).onRevert();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((ColorAndAppearanceFragment) getTargetFragment()).onApply();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
deleted file mode 100644
index dfacd03..0000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.tuner;
-
-import android.annotation.Nullable;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.support.v14.preference.PreferenceFragment;
-import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.DropDownPreference;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceViewHolder;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.SeekBar;
-import android.widget.Switch;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.policy.DisplayController;
-
-import java.util.Objects;
-
-public class ColorMatrixFragment extends PreferenceFragment implements TunerService.Tunable {
-
- private static final String TAG = "ColorMatrixFragment";
-
- private static final long RESET_DELAY = 10000;
-
- private boolean mCustomEnabled;
- private DropDownPreference mSelectPreference;
- private String mCurrentValue;
- private String mCustomValues;
- private SwitchPreference mEnableCustomPreference;
- private MatrixPreference mCustomPreference;
- private int mState;
- private Switch mSwitch;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Context context = getContext();
- TunerService.get(context).addTunable(this, DisplayController.COLOR_MATRIX_CUSTOM_ENABLED,
- DisplayController.COLOR_MATRIX_CUSTOM_VALUES, DisplayController.COLOR_STATE,
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- final View view = LayoutInflater.from(getContext()).inflate(
- R.layout.color_matrix_settings, container, false);
- ((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
- return view;
- }
-
- @Override
- public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
- final Context context = getPreferenceManager().getContext();
- setPreferenceScreen(getPreferenceManager().createPreferenceScreen(context));
-
- mSelectPreference = new DropDownPreference(context);
- mSelectPreference.setTitle(R.string.color_transform);
- mSelectPreference.setSummary("%s");
- mSelectPreference.setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (Objects.equals(newValue, DisplayController.AUTO_STRING)) {
- Settings.Secure.putInt(context.getContentResolver(),
- DisplayController.COLOR_STATE,
- DisplayController.COLOR_STATE_AUTO);
- return true;
- }
- if (Objects.equals(newValue, DisplayController.NONE_STRING)) {
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
- return true;
- }
- Settings.Secure.putInt(context.getContentResolver(),
- DisplayController.COLOR_STATE,
- DisplayController.COLOR_STATE_ENABLED);
- final String value = (String) newValue;
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
- value);
- return true;
- }
- });
- getPreferenceScreen().addPreference(mSelectPreference);
-
- mEnableCustomPreference = new SwitchPreference(context);
- mEnableCustomPreference.setTitle(R.string.color_enable_custom);
- mEnableCustomPreference.setOnPreferenceChangeListener(
- new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- boolean enabled = (Boolean) newValue;
- if (!enabled && Objects.equals(mCurrentValue, mCustomValues)) {
- Settings.Secure.putString(context.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
- }
- Settings.Secure.putInt(context.getContentResolver(),
- DisplayController.COLOR_MATRIX_CUSTOM_ENABLED, enabled ? 1 : 0);
- return true;
- }
- });
- getPreferenceScreen().addPreference(mEnableCustomPreference);
-
- mCustomPreference = new MatrixPreference(context);
- getPreferenceScreen().addPreference(mCustomPreference);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- View switchBar = view.findViewById(R.id.switch_bar);
- mSwitch = (Switch) switchBar.findViewById(android.R.id.switch_widget);
- mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
- switchBar.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- int newState = mState != DisplayController.COLOR_STATE_DISABLED
- ? DisplayController.COLOR_STATE_DISABLED
- : DisplayController.COLOR_STATE_ENABLED;
- ContentResolver contentResolver = getContext().getContentResolver();
- if (newState == DisplayController.COLOR_STATE_DISABLED) {
- String tiles = Settings.Secure.getString(contentResolver,
- QSTileHost.TILES_SETTING);
- if (tiles != null) {
- if (tiles.contains(",colors")) {
- tiles = tiles.replace(",colors", "");
- } else if (tiles.contains("colors,")) {
- tiles = tiles.replace("colors,", "");
- }
- Settings.Secure.putString(contentResolver, QSTileHost.TILES_SETTING,
- tiles);
- }
- }
- Settings.Secure.putInt(contentResolver,
- DisplayController.COLOR_STATE, newState);
- }
- });
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- TunerService.get(getContext()).removeTunable(this);
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (DisplayController.COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
- mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
- mEnableCustomPreference.setChecked(mCustomEnabled);
- mCustomPreference.setEnabled(mCustomEnabled
- && mState != DisplayController.COLOR_STATE_DISABLED);
- updateSelectOptions();
- } else if (DisplayController.COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
- mCustomValues = newValue;
- if (mCustomValues == null) {
- mCustomValues = DisplayController.toString(DisplayController.IDENTITY_MATRIX);
- }
- mCustomPreference.setValues(mCustomValues);
- updateSelectOptions();
- } else if (DisplayController.COLOR_STATE.equals(key)) {
- mState = newValue != null ? Integer.parseInt(newValue) : 0;
- if (mSwitch != null) {
- mSwitch.setChecked(mState != DisplayController.COLOR_STATE_DISABLED);
- }
- mSelectPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
- mEnableCustomPreference.setEnabled(mState != DisplayController.COLOR_STATE_DISABLED);
- mCustomPreference.setEnabled(mCustomEnabled
- && mState != DisplayController.COLOR_STATE_DISABLED);
- } else {
- mCurrentValue = newValue;
- updateSelectOptions();
- }
- }
-
- private void updateSelectOptions() {
- final int N = DisplayController.CUSTOM_INDEX + (mCustomEnabled ? 1 : 0);
- String[] values = new String[N];
- CharSequence[] names = new CharSequence[N];
- CharSequence[] totalNames = DisplayController.getColorTitles(getContext());
- String[] entries = DisplayController.getColorTransforms(getContext());
- entries[DisplayController.CUSTOM_INDEX] = mCustomValues != null ? mCustomValues : "";
- for (int i = 0; i < N; i++) {
- values[i] = entries[i];
- names[i] = totalNames[i];
- }
- mSelectPreference.setEntries(names);
- mSelectPreference.setEntryValues(values);
- int index = 0;
- if (mState == DisplayController.COLOR_STATE_AUTO) {
- index = DisplayController.AUTO_INDEX;
- } else if (mCustomValues != null && Objects.equals(mCurrentValue, mCustomValues)) {
- index = DisplayController.CUSTOM_INDEX;
- } else if (Objects.equals(mCurrentValue, entries[1])) {
- index = 1;
- }
- mSelectPreference.setValueIndex(index);
- mSelectPreference.setSummary("%s");
- return;
- }
-
- private void startRevertTimer() {
- getView().postDelayed(mResetColorMatrix, RESET_DELAY);
- }
-
- private void onApply() {
- Settings.Secure.putString(getContext().getContentResolver(),
- DisplayController.COLOR_MATRIX_CUSTOM_VALUES, mCurrentValue);
- getView().removeCallbacks(mResetColorMatrix);
- }
-
- private void onRevert() {
- getView().removeCallbacks(mResetColorMatrix);
- mResetColorMatrix.run();
- }
-
- private final Runnable mResetColorMatrix = new Runnable() {
- @Override
- public void run() {
- ((DialogFragment) getFragmentManager().findFragmentByTag("RevertWarning")).dismiss();
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
- }
- };
-
- private class MatrixPreference extends Preference implements View.OnClickListener {
- private float[] mValues;
-
- public MatrixPreference(Context context) {
- super(context);
- setLayoutResource(R.layout.preference_matrix);
- }
-
- public void setValues(String customValues) {
- String[] strValues = customValues.split(",");
- mValues = new float[strValues.length];
- for (int i = 0; i < mValues.length; i++) {
- mValues[i] = Float.parseFloat(strValues[i]);
- }
- notifyChanged();
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder holder) {
- super.onBindViewHolder(holder);
- bindView(holder.findViewById(R.id.r_group), 0);
- bindView(holder.findViewById(R.id.g_group), 5);
- bindView(holder.findViewById(R.id.b_group), 10);
- holder.findViewById(R.id.apply).setOnClickListener(this);
- }
-
- private void bindView(View view, final int index) {
- SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
- seekBar.setMax(1000);
- seekBar.setProgress((int) (1000 * mValues[index]));
- seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- mValues[index] = progress / 1000f;
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- }
-
- @Override
- public void onClick(View v) {
- startRevertTimer();
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
- DisplayController.toString(mValues));
- RevertWarning.show(ColorMatrixFragment.this);
- }
-
- }
-
- public static class RevertWarning extends DialogFragment
- implements DialogInterface.OnClickListener {
-
- public static void show(ColorMatrixFragment fragment) {
- RevertWarning warning = new RevertWarning();
- warning.setTargetFragment(fragment, 0);
- warning.show(fragment.getFragmentManager(), "RevertWarning");
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- AlertDialog alertDialog = new AlertDialog.Builder(getContext())
- .setTitle(R.string.color_revert_title)
- .setMessage(R.string.color_revert_message)
- .setPositiveButton(R.string.ok, this)
- .create();
- alertDialog.setCanceledOnTouchOutside(true);
- return alertDialog;
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- super.onCancel(dialog);
- ((ColorMatrixFragment) getTargetFragment()).onRevert();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- ((ColorMatrixFragment) getTargetFragment()).onApply();
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
deleted file mode 100644
index d8cf2e2..0000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.tuner;
-
-import android.app.ActivityManager;
-import android.provider.Settings;
-
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
-import com.android.systemui.qs.QSTile;
-import com.android.systemui.statusbar.policy.DisplayController;
-
-import java.util.Objects;
-
-
-public class ColorMatrixTile extends QSTile<QSTile.State> implements DisplayController.Listener {
-
- public static final String COLOR_MATRIX_SPEC = "colors";
-
- private final DisplayController mDisplayController;
-
- private int mIndex;
- private String mCurrentValue;
-
- private boolean mCustomEnabled;
- private String[] mValues;
- private CharSequence[] mValueTitles;
-
- public ColorMatrixTile(Host host) {
- super(host);
- mDisplayController = host.getDisplayController();
- }
-
- @Override
- public void setListening(boolean listening) {
- if (listening) {
- mValues = DisplayController.getColorTransforms(mContext);
- mValueTitles = DisplayController.getColorTitles(mContext);
- mDisplayController.addListener(this);
- } else {
- mDisplayController.removeListener(this);
- }
- }
-
- @Override
- public State newTileState() {
- return new State();
- }
-
- @Override
- protected void handleClick() {
- mIndex++;
- if (mIndex == DisplayController.AUTO_INDEX) {
- mDisplayController.setAuto(true);
- } else {
- mDisplayController.setAuto(false);
- if (!mDisplayController.isCustomEnabled()
- && (mIndex == DisplayController.CUSTOM_INDEX)) {
- mIndex++;
- }
- if (mIndex == mValues.length - 1) {
- mIndex = 0;
- }
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, mValues[mIndex],
- ActivityManager.getCurrentUser());
- }
- refreshState();
- }
-
- @Override
- protected void handleUpdateState(State state, Object arg) {
- if (mDisplayController.isAuto()) {
- mIndex = DisplayController.AUTO_INDEX;
- } else if (mDisplayController.isCustomSet()) {
- mIndex = DisplayController.CUSTOM_INDEX;
- } else {
- mIndex = Objects.equals(mDisplayController.getCurrentMatrix(), mValues[1]) ? 1 : 0;
- }
- state.icon = ResourceIcon.get(R.drawable.ic_colorize);
- state.label = mValueTitles[mIndex];
- state.contentDescription = mValueTitles[mIndex];
- }
-
- @Override
- public void onCurrentMatrixChanged() {
- refreshState();
- }
-
- @Override
- public int getMetricsCategory() {
- return MetricsEvent.QS_COLOR_MATRIX;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
index 5ded885..ad42459 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -117,13 +117,9 @@
if (isRotated) {
mPreview.findViewById(R.id.rot0).setVisibility(View.GONE);
final View rot90 = mPreview.findViewById(R.id.rot90);
- rot90.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
- rot90.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
} else {
mPreview.findViewById(R.id.rot90).setVisibility(View.GONE);
final View rot0 = mPreview.findViewById(R.id.rot0);
- rot0.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
- rot0.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
new file mode 100644
index 0000000..e9650ea
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeFragment.java
@@ -0,0 +1,195 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.tuner;
+
+import android.annotation.Nullable;
+import android.app.UiModeManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.DropDownPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Switch;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.NightModeController;
+import com.android.systemui.statusbar.policy.NightModeController.Listener;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+public class NightModeFragment extends PreferenceFragment implements Tunable,
+ Listener, OnPreferenceChangeListener {
+
+ private static final String TAG = "NightModeFragment";
+
+ public static final String EXTRA_SHOW_NIGHT_MODE = "show_night_mode";
+
+ private static final CharSequence KEY_AUTO = "auto";
+ private static final CharSequence KEY_DARK_THEME = "dark_theme";
+ private static final CharSequence KEY_ADJUST_TINT = "adjust_tint";
+ private static final CharSequence KEY_ADJUST_BRIGHTNESS = "adjust_brightness";
+
+ private Switch mSwitch;
+
+ private NightModeController mNightModeController;
+ private SwitchPreference mAutoSwitch;
+ private SwitchPreference mDarkTheme;
+ private SwitchPreference mAdjustTint;
+ private SwitchPreference mAdjustBrightness;
+ private UiModeManager mUiModeManager;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNightModeController = new NightModeController(getContext());
+ mUiModeManager = getContext().getSystemService(UiModeManager.class);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View view = LayoutInflater.from(getContext()).inflate(
+ R.layout.night_mode_settings, container, false);
+ ((ViewGroup) view).addView(super.onCreateView(inflater, container, savedInstanceState));
+ return view;
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ final Context context = getPreferenceManager().getContext();
+
+ addPreferencesFromResource(R.xml.night_mode);
+ mAutoSwitch = (SwitchPreference) findPreference(KEY_AUTO);
+ mAutoSwitch.setOnPreferenceChangeListener(this);
+ mDarkTheme = (SwitchPreference) findPreference(KEY_DARK_THEME);
+ mDarkTheme.setOnPreferenceChangeListener(this);
+ mAdjustTint = (SwitchPreference) findPreference(KEY_ADJUST_TINT);
+ mAdjustTint.setOnPreferenceChangeListener(this);
+ mAdjustBrightness = (SwitchPreference) findPreference(KEY_ADJUST_BRIGHTNESS);
+ mAdjustBrightness.setOnPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ View switchBar = view.findViewById(R.id.switch_bar);
+ mSwitch = (Switch) switchBar.findViewById(android.R.id.switch_widget);
+ mSwitch.setChecked(mNightModeController.isEnabled());
+ switchBar.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ boolean newState = !mNightModeController.isEnabled();
+ mNightModeController.setNightMode(newState);
+ mSwitch.setChecked(newState);
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mNightModeController.addListener(this);
+ TunerService.get(getContext()).addTunable(this, Secure.BRIGHTNESS_USE_TWILIGHT,
+ NightModeController.NIGHT_MODE_ADJUST_TINT);
+ mDarkTheme.setChecked(mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO);
+ calculateDisabled();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mNightModeController.removeListener(this);
+ TunerService.get(getContext()).removeTunable(this);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (mAutoSwitch == preference) {
+ mNightModeController.setAuto((Boolean) newValue);
+ } else if (mDarkTheme == preference) {
+ mUiModeManager.setNightMode(((Boolean) newValue) ? UiModeManager.MODE_NIGHT_AUTO
+ : UiModeManager.MODE_NIGHT_NO);
+ postCalculateDisabled();
+ } else if (mAdjustTint == preference) {
+ mNightModeController.setAdjustTint((Boolean) newValue);
+ postCalculateDisabled();
+ } else if (mAdjustBrightness == preference) {
+ TunerService.get(getContext()).setValue(Secure.BRIGHTNESS_USE_TWILIGHT,
+ ((Boolean) newValue) ? 1 : 0);
+ postCalculateDisabled();
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ private void postCalculateDisabled() {
+ // Post this because its the easiest way to wait for all state to be calculated.
+ getView().post(new Runnable() {
+ @Override
+ public void run() {
+ calculateDisabled();
+ }
+ });
+ }
+
+ private void calculateDisabled() {
+ int enabledCount = (mDarkTheme.isChecked() ? 1 : 0)
+ + (mAdjustTint.isChecked() ? 1 : 0)
+ + (mAdjustBrightness.isChecked() ? 1 : 0);
+ if (enabledCount == 1) {
+ if (mDarkTheme.isChecked()) {
+ mDarkTheme.setEnabled(false);
+ } else if (mAdjustTint.isChecked()) {
+ mAdjustTint.setEnabled(false);
+ } else {
+ mAdjustBrightness.setEnabled(false);
+ }
+ } else {
+ mDarkTheme.setEnabled(true);
+ mAdjustTint.setEnabled(true);
+ mAdjustBrightness.setEnabled(true);
+ }
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (Secure.BRIGHTNESS_USE_TWILIGHT.equals(key)) {
+ mAdjustBrightness.setChecked(newValue != null && Integer.parseInt(newValue) != 0);
+ } else if (NightModeController.NIGHT_MODE_ADJUST_TINT.equals(key)) {
+ // Default on.
+ mAdjustTint.setChecked(newValue == null || Integer.parseInt(newValue) != 0);
+ }
+ }
+
+ @Override
+ public void onNightModeChanged() {
+ mSwitch.setChecked(mNightModeController.isEnabled());
+ }
+
+ @Override
+ public void onTwilightAutoChanged() {
+ mAutoSwitch.setChecked(mNightModeController.isAuto());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
new file mode 100644
index 0000000..61135bd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.tuner;
+
+import android.app.ActivityManager;
+import android.content.Intent;
+import android.provider.Settings;
+
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.NightModeController;
+
+import java.util.Objects;
+
+
+public class NightModeTile extends QSTile<QSTile.State> implements NightModeController.Listener {
+
+ public static final String NIGHT_MODE_SPEC = "night";
+
+ private final NightModeController mNightModeController;
+
+ private int mIndex;
+ private String mCurrentValue;
+
+ private boolean mCustomEnabled;
+ private String[] mValues;
+ private CharSequence[] mValueTitles;
+
+ public NightModeTile(Host host) {
+ super(host);
+ mNightModeController = host.getNightModeController();
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ mNightModeController.addListener(this);
+ refreshState();
+ } else {
+ mNightModeController.removeListener(this);
+ }
+ }
+
+ @Override
+ public State newTileState() {
+ return new State();
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return new Intent(mContext, TunerActivity.class)
+ .putExtra(NightModeFragment.EXTRA_SHOW_NIGHT_MODE, true);
+ }
+
+ @Override
+ protected void handleClick() {
+ mNightModeController.setNightMode(!mNightModeController.isEnabled());
+ refreshState();
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ // TODO: Right now this is just a dropper, needs an actual night icon.
+ boolean enabled = mNightModeController.isEnabled();
+ state.icon = ResourceIcon.get(enabled ? R.drawable.ic_night_mode
+ : R.drawable.ic_night_mode_disabled);
+ state.label = mContext.getString(R.string.night_mode);
+ state.contentDescription = mContext.getString(R.string.night_mode);
+ }
+
+ @Override
+ public void onNightModeChanged() {
+ refreshState();
+ }
+
+ @Override
+ public void onTwilightAutoChanged() {
+ // Don't care.
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.QS_COLOR_MATRIX;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 4225b48..def597d 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -36,7 +36,10 @@
super.onCreate(savedInstanceState);
if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
- getFragmentManager().beginTransaction().replace(R.id.content_frame, new TunerFragment(),
+ boolean showNightMode = getIntent().getBooleanExtra(
+ NightModeFragment.EXTRA_SHOW_NIGHT_MODE, false);
+ getFragmentManager().beginTransaction().replace(R.id.content_frame,
+ showNightMode ? new NightModeFragment() : new TunerFragment(),
TAG_TUNER).commit();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 9df5368..70f2fdc 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -37,8 +37,6 @@
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
-import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
-
public class TunerFragment extends PreferenceFragment {
private static final String TAG = "TunerFragment";
@@ -51,10 +49,6 @@
private static final int MENU_REMOVE = Menu.FIRST + 1;
- private final SettingObserver mSettingObserver = new SettingObserver();
-
- private SwitchPreference mBatteryPct;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -72,7 +66,6 @@
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.tuner_prefs);
- mBatteryPct = (SwitchPreference) findPreference(KEY_BATTERY_PCT);
if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING,
0) == 0) {
if (getFragmentManager().findFragmentByTag(WARNING_TAG) == null) {
@@ -85,9 +78,6 @@
public void onResume() {
super.onResume();
getActivity().setTitle(R.string.system_ui_tuner);
- updateBatteryPct();
- getContext().getContentResolver().registerContentObserver(
- System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
MetricsLogger.visibility(getContext(), MetricsEvent.TUNER, true);
}
@@ -95,7 +85,6 @@
@Override
public void onPause() {
super.onPause();
- getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
MetricsLogger.visibility(getContext(), MetricsEvent.TUNER, false);
}
@@ -123,35 +112,6 @@
return super.onOptionsItemSelected(item);
}
- private void updateBatteryPct() {
- mBatteryPct.setOnPreferenceChangeListener(null);
- mBatteryPct.setChecked(System.getInt(getContext().getContentResolver(),
- SHOW_PERCENT_SETTING, 0) != 0);
- mBatteryPct.setOnPreferenceChangeListener(mBatteryPctChange);
- }
-
- private final class SettingObserver extends ContentObserver {
- public SettingObserver() {
- super(new Handler());
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- super.onChange(selfChange, uri, userId);
- updateBatteryPct();
- }
- }
-
- private final OnPreferenceChangeListener mBatteryPctChange = new OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final boolean v = (Boolean) newValue;
- MetricsLogger.action(getContext(), MetricsEvent.TUNER_BATTERY_PERCENTAGE, v);
- System.putInt(getContext().getContentResolver(), SHOW_PERCENT_SETTING, v ? 1 : 0);
- return true;
- }
- };
-
public static class TunerWarningFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index 7ad752e..b738136 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -23,7 +23,7 @@
@Override
public void onAttached() {
super.onAttached();
- TunerService.get(getContext()).addTunable(this, getKey());
+ TunerService.get(getContext()).addTunable(this, getKey().split(","));
}
@Override
@@ -39,7 +39,9 @@
@Override
protected boolean persistBoolean(boolean value) {
- Settings.Secure.putString(getContext().getContentResolver(), getKey(), value ? "1" : "0");
+ for (String key : getKey().split(",")) {
+ Settings.Secure.putString(getContext().getContentResolver(), key, value ? "1" : "0");
+ }
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
new file mode 100644
index 0000000..cc0ffb0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.tuner;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Checkable;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.systemui.Prefs;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.ZenModePanel;
+import com.android.systemui.volume.ZenModePanel.Callback;
+
+public class TunerZenModePanel extends LinearLayout implements OnClickListener {
+ private static final String TAG = "TunerZenModePanel";
+
+ private Callback mCallback;
+ private ZenModePanel mZenModePanel;
+ private View mHeaderSwitch;
+ private int mZenMode;
+ private ZenModeController mController;
+ private View mButtons;
+ private View mMoreSettings;
+ private View mDone;
+ private OnClickListener mDoneListener;
+ private boolean mEditing;
+
+ public TunerZenModePanel(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void init(ZenModeController zenModeController) {
+ mController = zenModeController;
+ mHeaderSwitch = findViewById(R.id.tuner_zen_switch);
+ mHeaderSwitch.setVisibility(View.VISIBLE);
+ mHeaderSwitch.setOnClickListener(this);
+ mHeaderSwitch.findViewById(com.android.internal.R.id.up).setVisibility(View.GONE);
+ ((TextView) mHeaderSwitch.findViewById(android.R.id.title)).setText(
+ R.string.quick_settings_dnd_label);
+ mZenModePanel = (ZenModePanel) findViewById(R.id.zen_mode_panel);
+ mZenModePanel.init(zenModeController);
+ mButtons = findViewById(R.id.tuner_zen_buttons);
+ mMoreSettings = mButtons.findViewById(android.R.id.button2);
+ mMoreSettings.setOnClickListener(this);
+ ((TextView) mMoreSettings).setText(R.string.quick_settings_more_settings);
+ mDone = mButtons.findViewById(android.R.id.button1);
+ mDone.setOnClickListener(this);
+ ((TextView) mDone).setText(R.string.quick_settings_done);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mEditing = false;
+ }
+
+ public void setCallback(Callback zenPanelCallback) {
+ mCallback = zenPanelCallback;
+ mZenModePanel.setCallback(zenPanelCallback);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == mHeaderSwitch) {
+ mEditing = true;
+ if (mZenMode == Global.ZEN_MODE_OFF) {
+ mZenMode = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN,
+ Global.ZEN_MODE_ALARMS);
+ mController.setZen(mZenMode, null, TAG);
+ postUpdatePanel();
+ } else {
+ mZenMode = Global.ZEN_MODE_OFF;
+ mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
+ postUpdatePanel();
+ }
+ } else if (v == mMoreSettings) {
+ Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getContext().startActivity(intent);
+ } else if (v == mDone) {
+ mEditing = false;
+ setVisibility(View.GONE);
+ mDoneListener.onClick(v);
+ }
+ }
+
+ public boolean isEditing() {
+ return mEditing;
+ }
+
+ public void setZenState(int zenMode) {
+ mZenMode = zenMode;
+ postUpdatePanel();
+ }
+
+ private void postUpdatePanel() {
+ // The complicated structure from reusing the same ZenPanel has resulted in some
+ // unstableness/flickering from callbacks coming in quickly. To solve this just
+ // post the UI updates a little bit.
+ removeCallbacks(mUpdate);
+ postDelayed(mUpdate, 40);
+ }
+
+ public void setDoneListener(OnClickListener onClickListener) {
+ mDoneListener = onClickListener;
+ }
+
+ private void updatePanel() {
+ boolean zenOn = mZenMode != Global.ZEN_MODE_OFF;
+ ((Checkable) mHeaderSwitch.findViewById(android.R.id.toggle)).setChecked(zenOn);
+ mZenModePanel.setVisibility(zenOn ? View.VISIBLE : View.GONE);
+ mButtons.setVisibility(zenOn ? View.VISIBLE : View.GONE);
+ }
+
+ private final Runnable mUpdate = new Runnable() {
+ @Override
+ public void run() {
+ updatePanel();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 6aae9bd..1810c1c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -67,6 +67,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerZenModePanel;
import com.android.systemui.volume.VolumeDialogController.State;
import com.android.systemui.volume.VolumeDialogController.StreamState;
@@ -133,7 +134,7 @@
private int mLastActiveStream;
private boolean mShowFullZen;
- private final ZenModePanel mZenPanel;
+ private final TunerZenModePanel mZenPanel;
public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
ZenModeController zenModeController, Callback callback) {
@@ -225,8 +226,7 @@
mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
mZenFooter.init(zenModeController);
- mZenPanel = (ZenModePanel) mDialog.findViewById(R.id.zen_mode_panel);
- mZenPanel.addNoneButton();
+ mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel);
mZenPanel.init(zenModeController);
mZenPanel.setCallback(mZenPanelCallback);
@@ -671,7 +671,7 @@
final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
&& (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
- && !mShowFullZen;
+ && !mZenPanel.isEditing();
if (wasVisible != visible && !visible) {
prepareForCollapse();
}
@@ -679,12 +679,21 @@
mZenFooter.update();
final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE;
- final boolean fullVisible = mShowFullZen && (mState.zenMode != Global.ZEN_MODE_OFF
- || mExpanded);
+ final boolean fullVisible = mShowFullZen && !visible;
if (fullWasVisible != fullVisible && !fullVisible) {
prepareForCollapse();
}
Util.setVisOrGone(mZenPanel, fullVisible);
+ if (fullVisible) {
+ mZenPanel.setZenState(mState.zenMode);
+ mZenPanel.setDoneListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ prepareForCollapse();
+ mHandler.sendEmptyMessage(H.UPDATE_FOOTER);
+ }
+ });
+ }
}
private void updateVolumeRowH(VolumeRow row) {
@@ -978,6 +987,7 @@
private static final int RESCHEDULE_TIMEOUT = 6;
private static final int STATE_CHANGED = 7;
private static final int UPDATE_BOTTOM_MARGIN = 8;
+ private static final int UPDATE_FOOTER = 9;
public H() {
super(Looper.getMainLooper());
@@ -994,6 +1004,7 @@
case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break;
case STATE_CHANGED: onStateChangedH(mState); break;
case UPDATE_BOTTOM_MARGIN: updateDialogBottomMarginH(); break;
+ case UPDATE_FOOTER: updateFooterH(); break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 5ca24f7..6976c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -190,12 +190,6 @@
mZenAlarmWarning = (TextView) findViewById(R.id.zen_alarm_warning);
}
- public void addNoneButton() {
- mZenButtons.addButton(R.string.interruption_level_all_twoline,
- R.string.interruption_level_all,
- Global.ZEN_MODE_OFF);
- }
-
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
diff --git a/preloaded-classes b/preloaded-classes
index 2301c41..9535cc2 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1,4 +1,3 @@
-# Classes which are preloaded by com.android.internal.os.ZygoteInit.
[B
[C
[D
@@ -10,6 +9,7 @@
[Landroid.animation.Keyframe$FloatKeyframe;
[Landroid.animation.Keyframe$IntKeyframe;
[Landroid.animation.Keyframe$ObjectKeyframe;
+[Landroid.animation.Keyframe;
[Landroid.animation.PropertyValuesHolder;
[Landroid.app.LoaderManagerImpl;
[Landroid.content.ContentProviderResult;
@@ -26,12 +26,16 @@
[Landroid.content.pm.ProviderInfo;
[Landroid.content.pm.ServiceInfo;
[Landroid.content.pm.Signature;
+[Landroid.content.res.Configuration;
[Landroid.content.res.StringBlock;
[Landroid.content.res.XmlBlock;
+[Landroid.database.Cursor;
[Landroid.database.CursorWindow;
[Landroid.database.sqlite.SQLiteConnection$Operation;
[Landroid.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus;
+[Landroid.graphics.Bitmap$CompressFormat;
[Landroid.graphics.Bitmap$Config;
+[Landroid.graphics.Bitmap;
[Landroid.graphics.Canvas$EdgeType;
[Landroid.graphics.FontFamily;
[Landroid.graphics.Interpolator$Result;
@@ -50,10 +54,12 @@
[Landroid.graphics.drawable.GradientDrawable$Orientation;
[Landroid.graphics.drawable.LayerDrawable$ChildDrawable;
[Landroid.graphics.drawable.RippleForeground;
+[Landroid.hardware.display.WifiDisplay;
[Landroid.hardware.soundtrigger.SoundTrigger$ConfidenceLevel;
[Landroid.hardware.soundtrigger.SoundTrigger$Keyphrase;
[Landroid.hardware.soundtrigger.SoundTrigger$KeyphraseRecognitionExtra;
[Landroid.icu.impl.ICUResourceBundle$OpenType;
+[Landroid.icu.impl.StandardPlural;
[Landroid.icu.impl.Trie2$ValueWidth;
[Landroid.icu.impl.UCharacterProperty$BinaryProperty;
[Landroid.icu.impl.UCharacterProperty$IntProperty;
@@ -67,17 +73,17 @@
[Landroid.icu.text.MessagePattern$ApostropheMode;
[Landroid.icu.text.MessagePattern$ArgType;
[Landroid.icu.text.MessagePattern$Part$Type;
+[Landroid.icu.text.PluralRules$Operand;
+[Landroid.icu.text.PluralRules$PluralType;
+[Landroid.icu.text.PluralRules$SampleType;
[Landroid.icu.text.UnicodeSet;
[Landroid.icu.util.BytesTrie$Result;
[Landroid.icu.util.Calendar$CalType;
+[Landroid.icu.util.Currency$CurrencyUsage;
[Landroid.icu.util.ULocale$Category;
[Landroid.icu.util.ULocale;
-[Landroid.media.AudioDeviceInfo;
[Landroid.media.AudioGain;
-[Landroid.media.AudioPatch;
-[Landroid.media.AudioPort;
-[Landroid.media.AudioPortConfig;
-[Landroid.media.MediaTimeProvider$OnMediaTimeListener;
+[Landroid.net.Network;
[Landroid.net.NetworkInfo$DetailedState;
[Landroid.net.NetworkInfo$State;
[Landroid.net.Uri;
@@ -85,6 +91,7 @@
[Landroid.os.AsyncTask$Status;
[Landroid.os.MessageQueue$IdleHandler;
[Landroid.os.Parcel;
+[Landroid.os.ParcelFileDescriptor;
[Landroid.os.Parcelable;
[Landroid.os.PatternMatcher;
[Landroid.os.storage.StorageVolume;
@@ -102,6 +109,7 @@
[Landroid.text.method.TextKeyListener;
[Landroid.text.style.AlignmentSpan;
[Landroid.text.style.CharacterStyle;
+[Landroid.text.style.ClickableSpan;
[Landroid.text.style.LeadingMarginSpan;
[Landroid.text.style.LineBackgroundSpan;
[Landroid.text.style.LineHeightSpan;
@@ -114,9 +122,13 @@
[Landroid.text.style.URLSpan;
[Landroid.text.style.WrapTogetherSpan;
[Landroid.util.LongSparseArray;
-[Landroid.util.PathParser$PathDataNode;
+[Landroid.util.Pair;
+[Landroid.util.Rational;
[Landroid.view.Choreographer$CallbackQueue;
+[Landroid.view.Display$ColorTransform;
[Landroid.view.Display$Mode;
+[Landroid.view.Display;
+[Landroid.view.HandlerActionQueue$HandlerAction;
[Landroid.view.MenuItem;
[Landroid.view.View;
[Landroid.widget.Editor$TextRenderNode;
@@ -130,17 +142,19 @@
[Lcom.android.internal.telephony.PhoneConstants$State;
[Lcom.android.okhttp.CipherSuite;
[Lcom.android.okhttp.ConnectionSpec;
+[Lcom.android.okhttp.HttpUrl$Builder$ParseResult;
[Lcom.android.okhttp.Protocol;
[Lcom.android.okhttp.TlsVersion;
[Lcom.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
-[Lcom.android.org.bouncycastle.asn1.x500.RDN;
-[Lcom.android.org.bouncycastle.asn1.x509.GeneralName;
[Lcom.android.org.conscrypt.OpenSSLX509CertPath$Encoding;
[Lcom.android.org.conscrypt.OpenSSLX509Certificate;
[Ldalvik.system.DexPathList$Element;
+[Ljava.beans.PropertyChangeListener;
+[Ljava.io.File$PathStatus;
[Ljava.io.File;
[Ljava.io.FileDescriptor;
[Ljava.io.IOException;
+[Ljava.io.ObjectInputStream$HandleTable$HandleList;
[Ljava.io.ObjectStreamField;
[Ljava.lang.Byte;
[Ljava.lang.CharSequence;
@@ -159,9 +173,11 @@
[Ljava.lang.Thread$State;
[Ljava.lang.Thread;
[Ljava.lang.ThreadGroup;
+[Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;
[Ljava.lang.Throwable;
[Ljava.lang.Void;
[Ljava.lang.annotation.Annotation;
+[Ljava.lang.ref.WeakReference;
[Ljava.lang.reflect.AccessibleObject;
[Ljava.lang.reflect.Constructor;
[Ljava.lang.reflect.Field;
@@ -173,18 +189,24 @@
[Ljava.math.RoundingMode;
[Ljava.net.InetAddress;
[Ljava.net.Proxy$Type;
+[Ljava.nio.ByteBuffer;
+[Ljava.security.CryptoPrimitive;
+[Ljava.security.Principal;
[Ljava.security.Provider;
[Ljava.security.cert.Certificate;
[Ljava.security.cert.X509Certificate;
-[Ljava.text.Format$Field;
+[Ljava.text.DateFormat$Field;
+[Ljava.text.Normalizer$Form;
[Ljava.util.ArrayList;
+[Ljava.util.Enumeration;
+[Ljava.util.Formatter$Flags;
+[Ljava.util.Formatter$FormatString;
[Ljava.util.HashMap$HashMapEntry;
[Ljava.util.Hashtable$HashtableEntry;
+[Ljava.util.Locale$Category;
[Ljava.util.Locale;
[Ljava.util.Map$Entry;
[Ljava.util.TimerTask;
-[Ljava.util.TreeMap$Bound;
-[Ljava.util.TreeMap$Relation;
[Ljava.util.WeakHashMap$Entry;
[Ljava.util.concurrent.ConcurrentHashMap$Node;
[Ljava.util.concurrent.ConcurrentHashMap$Segment;
@@ -192,32 +214,40 @@
[Ljava.util.concurrent.TimeUnit;
[Ljava.util.logging.Handler;
[Ljava.util.regex.Pattern;
+[Ljavax.crypto.Cipher$InitType;
[Ljavax.crypto.Cipher$NeedToSet;
+[Ljavax.microedition.khronos.egl.EGLConfig;
[Ljavax.net.ssl.KeyManager;
+[Ljavax.net.ssl.SSLSession;
[Ljavax.net.ssl.TrustManager;
+[Ljavax.security.auth.x500.X500Principal;
[Ljavax.security.cert.X509Certificate;
+[Llibcore.io.ClassPathURLStreamHandler;
[Llibcore.reflect.AnnotationMember$DefaultValues;
[Llibcore.reflect.AnnotationMember;
-[Lorg.apache.harmony.security.asn1.ASN1Type;
-[Lorg.apache.harmony.security.utils.ObjectIdentifier;
[Lorg.apache.http.Header;
-[Lorg.apache.http.HeaderElement;
-[Lorg.apache.http.NameValuePair;
-[Lorg.apache.http.conn.routing.RouteInfo$LayerType;
-[Lorg.apache.http.conn.routing.RouteInfo$TunnelType;
[Lorg.json.JSONStringer$Scope;
[Lorg.kxml2.io.KXmlParser$ValueContext;
+[Lsun.misc.FormattedFloatingDecimal$Form;
+[Lsun.security.jca.ProviderConfig;
+[Lsun.security.jca.ServiceId;
+[Lsun.security.pkcs.SignerInfo;
+[Lsun.security.util.DerOutputStream;
+[Lsun.security.util.DerValue;
+[Lsun.security.util.DisabledAlgorithmConstraints$KeySizeConstraint$Operator;
+[Lsun.security.util.ObjectIdentifier;
+[Lsun.security.x509.AVA;
+[Lsun.security.x509.RDN;
+[Lsun.util.logging.PlatformLogger$Level;
[S
[Z
[[B
-[[C
[[I
-[[Lcom.android.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+[[Ljava.lang.Byte;
[[Ljava.lang.Class;
[[Ljava.lang.Object;
[[Ljava.lang.String;
[[Ljava.lang.annotation.Annotation;
-[[Lorg.apache.harmony.security.utils.ObjectIdentifier;
[[S
[[[I
android.R$styleable
@@ -240,17 +270,22 @@
android.accounts.IAccountManagerResponse$Stub
android.accounts.OnAccountsUpdateListener
android.accounts.OperationCanceledException
+android.animation.AnimationHandler
+android.animation.AnimationHandler$1
+android.animation.AnimationHandler$2
+android.animation.AnimationHandler$AnimationFrameCallback
+android.animation.AnimationHandler$AnimationFrameCallbackProvider
+android.animation.AnimationHandler$MyFrameCallbackProvider
android.animation.Animator
android.animation.Animator$AnimatorConstantState
android.animation.Animator$AnimatorListener
android.animation.Animator$AnimatorPauseListener
android.animation.AnimatorInflater
+android.animation.AnimatorInflater$PathDataEvaluator
android.animation.AnimatorListenerAdapter
android.animation.AnimatorSet
android.animation.AnimatorSet$AnimatorSetListener
android.animation.AnimatorSet$Builder
-android.animation.AnimatorSet$Dependency
-android.animation.AnimatorSet$DependencyListener
android.animation.AnimatorSet$Node
android.animation.ArgbEvaluator
android.animation.FloatEvaluator
@@ -272,10 +307,12 @@
android.animation.PathKeyframes$1
android.animation.PathKeyframes$2
android.animation.PathKeyframes$FloatKeyframesBase
+android.animation.PathKeyframes$IntKeyframesBase
android.animation.PathKeyframes$SimpleKeyframes
android.animation.PropertyValuesHolder
android.animation.PropertyValuesHolder$FloatPropertyValuesHolder
android.animation.PropertyValuesHolder$IntPropertyValuesHolder
+android.animation.PropertyValuesHolder$PropertyValues
android.animation.RectEvaluator
android.animation.StateListAnimator
android.animation.StateListAnimator$1
@@ -284,31 +321,34 @@
android.animation.TimeInterpolator
android.animation.TypeEvaluator
android.animation.ValueAnimator
-android.animation.ValueAnimator$AnimationHandler
-android.animation.ValueAnimator$AnimationHandler$1
-android.animation.ValueAnimator$AnimationHandler$2
android.animation.ValueAnimator$AnimatorUpdateListener
android.app.ActionBar
android.app.ActionBar$LayoutParams
android.app.Activity
android.app.Activity$HostCallbacks
android.app.ActivityManager
+android.app.ActivityManager$MemoryInfo
+android.app.ActivityManager$RecentTaskInfo
android.app.ActivityManager$RunningAppProcessInfo
android.app.ActivityManager$RunningAppProcessInfo$1
+android.app.ActivityManager$StackId
android.app.ActivityManager$TaskDescription
android.app.ActivityManager$TaskDescription$1
android.app.ActivityManagerNative
android.app.ActivityManagerNative$1
android.app.ActivityManagerProxy
+android.app.ActivityOptions
android.app.ActivityThread
android.app.ActivityThread$1
android.app.ActivityThread$2
android.app.ActivityThread$3
android.app.ActivityThread$ActivityClientRecord
+android.app.ActivityThread$ActivityConfigChangeData
android.app.ActivityThread$AppBindData
android.app.ActivityThread$ApplicationThread
android.app.ActivityThread$BindServiceData
android.app.ActivityThread$ContextCleanupInfo
+android.app.ActivityThread$CreateBackupAgentData
android.app.ActivityThread$CreateServiceData
android.app.ActivityThread$DropBoxReporter
android.app.ActivityThread$EventLoggingReporter
@@ -343,6 +383,7 @@
android.app.Dialog
android.app.Dialog$1
android.app.Dialog$ListenersHandler
+android.app.DialogFragment
android.app.DownloadManager
android.app.Fragment
android.app.Fragment$1
@@ -361,6 +402,8 @@
android.app.IAlarmManager$Stub
android.app.IAlarmManager$Stub$Proxy
android.app.IApplicationThread
+android.app.IBackupAgent
+android.app.IBackupAgent$Stub
android.app.IInstrumentationWatcher
android.app.IInstrumentationWatcher$Stub
android.app.INotificationManager
@@ -368,6 +411,8 @@
android.app.INotificationManager$Stub$Proxy
android.app.IServiceConnection
android.app.IServiceConnection$Stub
+android.app.ITransientNotification
+android.app.ITransientNotification$Stub
android.app.IUiAutomationConnection
android.app.IUiAutomationConnection$Stub
android.app.Instrumentation
@@ -391,10 +436,11 @@
android.app.NativeActivity
android.app.Notification
android.app.Notification$1
+android.app.Notification$Action
+android.app.Notification$BigTextStyle
android.app.Notification$Builder
-android.app.Notification$BuilderRemoteViews
+android.app.Notification$Style
android.app.NotificationManager
-android.app.OnActivityPausedListener
android.app.PendingIntent
android.app.PendingIntent$1
android.app.PendingIntent$CanceledException
@@ -481,11 +527,14 @@
android.app.SystemServiceRegistry$66
android.app.SystemServiceRegistry$67
android.app.SystemServiceRegistry$68
+android.app.SystemServiceRegistry$69
android.app.SystemServiceRegistry$7
+android.app.SystemServiceRegistry$70
android.app.SystemServiceRegistry$8
android.app.SystemServiceRegistry$9
android.app.SystemServiceRegistry$CachedServiceFetcher
android.app.SystemServiceRegistry$ServiceFetcher
+android.app.SystemServiceRegistry$StaticOuterContextServiceFetcher
android.app.SystemServiceRegistry$StaticServiceFetcher
android.app.UiModeManager
android.app.WallpaperManager
@@ -493,12 +542,15 @@
android.app.admin.IDevicePolicyManager
android.app.admin.IDevicePolicyManager$Stub
android.app.admin.IDevicePolicyManager$Stub$Proxy
+android.app.backup.BackupAgent
+android.app.backup.BackupAgent$BackupServiceBinder
+android.app.backup.BackupAgent$SharedPrefsSynchronizer
+android.app.backup.BackupAgentHelper
android.app.backup.BackupDataInput
android.app.backup.BackupDataInput$EntityHeader
android.app.backup.BackupDataOutput
android.app.backup.BackupHelperDispatcher
android.app.backup.BackupHelperDispatcher$Header
-android.app.backup.BackupManager
android.app.backup.FileBackupHelperBase
android.app.backup.FullBackup
android.app.backup.FullBackupDataOutput
@@ -514,12 +566,14 @@
android.app.usage.UsageStatsManager
android.appwidget.AppWidgetManager
android.appwidget.AppWidgetProvider
+android.auditing.SecurityLog
+android.auditing.SecurityLog$SecurityEvent
+android.auditing.SecurityLog$SecurityEvent$1
android.bluetooth.BluetoothAdapter
android.bluetooth.BluetoothAdapter$1
android.bluetooth.BluetoothManager
android.bluetooth.IBluetooth
android.bluetooth.IBluetooth$Stub
-android.bluetooth.IBluetooth$Stub$Proxy
android.bluetooth.IBluetoothManager
android.bluetooth.IBluetoothManager$Stub
android.bluetooth.IBluetoothManager$Stub$Proxy
@@ -531,8 +585,9 @@
android.content.ActivityNotFoundException
android.content.BroadcastReceiver
android.content.BroadcastReceiver$PendingResult
-android.content.BroadcastReceiver$PendingResult$1
android.content.ClipData
+android.content.ClipData$1
+android.content.ClipData$Item
android.content.ClipDescription
android.content.ClipDescription$1
android.content.ClipboardManager
@@ -545,10 +600,9 @@
android.content.ContentProviderClient
android.content.ContentProviderNative
android.content.ContentProviderOperation
-android.content.ContentProviderOperation$1
+android.content.ContentProviderOperation$Builder
android.content.ContentProviderProxy
android.content.ContentProviderResult
-android.content.ContentProviderResult$1
android.content.ContentResolver
android.content.ContentResolver$CursorWrapperInner
android.content.ContentResolver$ParcelFileDescriptorInner
@@ -583,6 +637,7 @@
android.content.IntentSender
android.content.IntentSender$SendIntentException
android.content.OperationApplicationException
+android.content.PeriodicSync
android.content.RestrictionsManager
android.content.ServiceConnection
android.content.SharedPreferences
@@ -620,6 +675,8 @@
android.content.pm.LauncherApps
android.content.pm.PackageInfo
android.content.pm.PackageInfo$1
+android.content.pm.PackageInstaller
+android.content.pm.PackageInstaller$SessionInfo
android.content.pm.PackageItemInfo
android.content.pm.PackageManager
android.content.pm.PackageManager$NameNotFoundException
@@ -646,14 +703,17 @@
android.content.res.AssetManager$AssetInputStream
android.content.res.ColorStateList
android.content.res.ColorStateList$1
+android.content.res.ColorStateList$ColorStateListFactory
android.content.res.CompatibilityInfo
android.content.res.CompatibilityInfo$1
android.content.res.CompatibilityInfo$2
+android.content.res.ComplexColor
android.content.res.Configuration
android.content.res.Configuration$1
android.content.res.ConfigurationBoundResourceCache
android.content.res.ConstantState
android.content.res.DrawableCache
+android.content.res.GradientColor
android.content.res.ObbInfo
android.content.res.ObbInfo$1
android.content.res.ObbScanner
@@ -685,6 +745,7 @@
android.database.CrossProcessCursor
android.database.CrossProcessCursorWrapper
android.database.Cursor
+android.database.CursorIndexOutOfBoundsException
android.database.CursorToBulkCursorAdaptor
android.database.CursorToBulkCursorAdaptor$ContentObserverProxy
android.database.CursorWindow
@@ -700,6 +761,8 @@
android.database.IContentObserver$Stub
android.database.IContentObserver$Stub$Proxy
android.database.MatrixCursor
+android.database.MatrixCursor$RowBuilder
+android.database.MergeCursor
android.database.Observable
android.database.SQLException
android.database.sqlite.DatabaseObjectNotClosedException
@@ -712,11 +775,13 @@
android.database.sqlite.SQLiteConnectionPool
android.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus
android.database.sqlite.SQLiteConnectionPool$ConnectionWaiter
+android.database.sqlite.SQLiteConstraintException
android.database.sqlite.SQLiteCursor
android.database.sqlite.SQLiteCursorDriver
android.database.sqlite.SQLiteCustomFunction
android.database.sqlite.SQLiteDatabase
android.database.sqlite.SQLiteDatabase$1
+android.database.sqlite.SQLiteDatabase$CursorFactory
android.database.sqlite.SQLiteDatabaseConfiguration
android.database.sqlite.SQLiteDatabaseCorruptException
android.database.sqlite.SQLiteDatabaseLockedException
@@ -745,7 +810,7 @@
android.graphics.AvoidXfermode
android.graphics.Bitmap
android.graphics.Bitmap$1
-android.graphics.Bitmap$BitmapFinalizer
+android.graphics.Bitmap$CompressFormat
android.graphics.Bitmap$Config
android.graphics.BitmapFactory
android.graphics.BitmapFactory$Options
@@ -754,11 +819,11 @@
android.graphics.BlurMaskFilter
android.graphics.Camera
android.graphics.Canvas
-android.graphics.Canvas$CanvasFinalizer
android.graphics.Canvas$EdgeType
android.graphics.CanvasProperty
android.graphics.Color
android.graphics.ColorFilter
+android.graphics.ColorMatrix
android.graphics.ColorMatrixColorFilter
android.graphics.ComposePathEffect
android.graphics.ComposeShader
@@ -770,6 +835,7 @@
android.graphics.FontFamily
android.graphics.FontListParser
android.graphics.FontListParser$Alias
+android.graphics.FontListParser$Axis
android.graphics.FontListParser$Config
android.graphics.FontListParser$Family
android.graphics.FontListParser$Font
@@ -808,6 +874,7 @@
android.graphics.Point$1
android.graphics.PointF
android.graphics.PointF$1
+android.graphics.PorterDuff
android.graphics.PorterDuff$Mode
android.graphics.PorterDuffColorFilter
android.graphics.PorterDuffXfermode
@@ -836,11 +903,11 @@
android.graphics.drawable.Animatable2
android.graphics.drawable.AnimatedStateListDrawable
android.graphics.drawable.AnimatedStateListDrawable$AnimatedStateListState
-android.graphics.drawable.AnimatedStateListDrawable$Transition
android.graphics.drawable.AnimatedVectorDrawable
android.graphics.drawable.AnimatedVectorDrawable$1
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState
android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator
+android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator
android.graphics.drawable.AnimationDrawable
android.graphics.drawable.AnimationDrawable$AnimationState
android.graphics.drawable.BitmapDrawable
@@ -852,7 +919,7 @@
android.graphics.drawable.Drawable$ConstantState
android.graphics.drawable.DrawableContainer
android.graphics.drawable.DrawableContainer$DrawableContainerState
-android.graphics.drawable.DrawableContainer$DrawableContainerState$ConstantStateFuture
+android.graphics.drawable.DrawableInflater
android.graphics.drawable.DrawableWrapper
android.graphics.drawable.DrawableWrapper$DrawableWrapperState
android.graphics.drawable.GradientDrawable
@@ -892,9 +959,11 @@
android.graphics.drawable.TransitionDrawable$TransitionState
android.graphics.drawable.VectorDrawable
android.graphics.drawable.VectorDrawable$VFullPath
+android.graphics.drawable.VectorDrawable$VFullPath$1
android.graphics.drawable.VectorDrawable$VGroup
+android.graphics.drawable.VectorDrawable$VGroup$1
+android.graphics.drawable.VectorDrawable$VObject
android.graphics.drawable.VectorDrawable$VPath
-android.graphics.drawable.VectorDrawable$VPathRenderer
android.graphics.drawable.VectorDrawable$VectorDrawableState
android.graphics.drawable.shapes.OvalShape
android.graphics.drawable.shapes.RectShape
@@ -913,7 +982,10 @@
android.hardware.SerialPort
android.hardware.SystemSensorManager
android.hardware.SystemSensorManager$BaseEventQueue
+android.hardware.camera2.CameraCharacteristics$Key
android.hardware.camera2.CameraManager
+android.hardware.camera2.CaptureRequest$Key
+android.hardware.camera2.CaptureResult$Key
android.hardware.camera2.DngCreator
android.hardware.camera2.impl.CameraMetadataNative
android.hardware.camera2.legacy.LegacyCameraDevice
@@ -928,6 +1000,12 @@
android.hardware.display.IDisplayManager$Stub$Proxy
android.hardware.display.IDisplayManagerCallback
android.hardware.display.IDisplayManagerCallback$Stub
+android.hardware.display.WifiDisplay
+android.hardware.display.WifiDisplay$1
+android.hardware.display.WifiDisplaySessionInfo
+android.hardware.display.WifiDisplaySessionInfo$1
+android.hardware.display.WifiDisplayStatus
+android.hardware.display.WifiDisplayStatus$1
android.hardware.fingerprint.FingerprintManager
android.hardware.hdmi.HdmiControlManager
android.hardware.input.IInputDevicesChangedListener
@@ -939,6 +1017,10 @@
android.hardware.input.InputDeviceIdentifier$1
android.hardware.input.InputManager
android.hardware.input.InputManager$InputDevicesChangedListener
+# These cannot be preloaded and need to be refactored into system server. b/17791590, b/21935130
+# android.hardware.location.ActivityRecognitionHardware
+# android.hardware.location.IActivityRecognitionHardware
+# android.hardware.location.IActivityRecognitionHardware$Stub
android.hardware.radio.RadioManager
android.hardware.radio.RadioManager$AmBandConfig
android.hardware.radio.RadioManager$AmBandConfig$1
@@ -963,6 +1045,8 @@
android.hardware.soundtrigger.SoundTrigger
android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel
android.hardware.soundtrigger.SoundTrigger$ConfidenceLevel$1
+android.hardware.soundtrigger.SoundTrigger$GenericRecognitionEvent
+android.hardware.soundtrigger.SoundTrigger$GenericSoundModel
android.hardware.soundtrigger.SoundTrigger$Keyphrase
android.hardware.soundtrigger.SoundTrigger$Keyphrase$1
android.hardware.soundtrigger.SoundTrigger$KeyphraseRecognitionEvent
@@ -981,14 +1065,19 @@
android.hardware.soundtrigger.SoundTrigger$SoundModelEvent
android.hardware.soundtrigger.SoundTrigger$SoundModelEvent$1
android.hardware.soundtrigger.SoundTriggerModule
+android.hardware.usb.IUsbManager
+android.hardware.usb.IUsbManager$Stub
+android.hardware.usb.IUsbManager$Stub$Proxy
android.hardware.usb.UsbDevice
android.hardware.usb.UsbDeviceConnection
+android.hardware.usb.UsbInterface
android.hardware.usb.UsbManager
android.hardware.usb.UsbRequest
android.icu.impl.BMPSet
android.icu.impl.CacheBase
android.icu.impl.CalendarData
android.icu.impl.CalendarUtil
+android.icu.impl.CharTrie
android.icu.impl.ClassLoaderUtil
android.icu.impl.CurrencyData
android.icu.impl.CurrencyData$CurrencyDisplayInfo
@@ -1012,8 +1101,17 @@
android.icu.impl.ICUCurrencyMetaInfo$UniqueList
android.icu.impl.ICUData
android.icu.impl.ICUDebug
+android.icu.impl.ICULocaleService
+android.icu.impl.ICULocaleService$ICUResourceBundleFactory
+android.icu.impl.ICULocaleService$LocaleKey
+android.icu.impl.ICULocaleService$LocaleKeyFactory
+android.icu.impl.ICUNotifier
+android.icu.impl.ICURWLock
android.icu.impl.ICUResourceBundle
android.icu.impl.ICUResourceBundle$1
+android.icu.impl.ICUResourceBundle$2
+android.icu.impl.ICUResourceBundle$2$1
+android.icu.impl.ICUResourceBundle$AvailEntry
android.icu.impl.ICUResourceBundle$OpenType
android.icu.impl.ICUResourceBundle$WholeBundle
android.icu.impl.ICUResourceBundleImpl
@@ -1027,27 +1125,52 @@
android.icu.impl.ICUResourceBundleReader
android.icu.impl.ICUResourceBundleReader$Array
android.icu.impl.ICUResourceBundleReader$Array16
+android.icu.impl.ICUResourceBundleReader$Array32
android.icu.impl.ICUResourceBundleReader$Container
android.icu.impl.ICUResourceBundleReader$IsAcceptable
android.icu.impl.ICUResourceBundleReader$ReaderCache
-android.icu.impl.ICUResourceBundleReader$ReaderInfo
+android.icu.impl.ICUResourceBundleReader$ReaderCacheKey
android.icu.impl.ICUResourceBundleReader$ResourceCache
android.icu.impl.ICUResourceBundleReader$ResourceCache$Level
android.icu.impl.ICUResourceBundleReader$Table
android.icu.impl.ICUResourceBundleReader$Table16
android.icu.impl.ICUResourceBundleReader$Table1632
+android.icu.impl.ICUService
+android.icu.impl.ICUService$CacheEntry
+android.icu.impl.ICUService$Factory
+android.icu.impl.ICUService$Key
+android.icu.impl.IDNA2003
android.icu.impl.JavaTimeZone
android.icu.impl.LocaleIDParser
android.icu.impl.LocaleIDs
+android.icu.impl.Norm2AllModes
+android.icu.impl.Norm2AllModes$1
+android.icu.impl.Norm2AllModes$ComposeNormalizer2
+android.icu.impl.Norm2AllModes$DecomposeNormalizer2
+android.icu.impl.Norm2AllModes$FCDNormalizer2
+android.icu.impl.Norm2AllModes$NFCSingleton
+android.icu.impl.Norm2AllModes$NFKCSingleton
+android.icu.impl.Norm2AllModes$NoopNormalizer2
+android.icu.impl.Norm2AllModes$Norm2AllModesSingleton
+android.icu.impl.Norm2AllModes$Normalizer2WithImpl
+android.icu.impl.Normalizer2Impl
+android.icu.impl.Normalizer2Impl$1
+android.icu.impl.Normalizer2Impl$IsAcceptable
android.icu.impl.OlsonTimeZone
android.icu.impl.Pair
android.icu.impl.PatternProps
android.icu.impl.PatternTokenizer
+android.icu.impl.PluralRulesLoader
android.icu.impl.ReplaceableUCharacterIterator
android.icu.impl.RuleCharacterIterator
android.icu.impl.SimpleCache
android.icu.impl.SoftCache
android.icu.impl.SoftCache$SettableSoftReference
+android.icu.impl.StandardPlural
+android.icu.impl.StringPrepDataReader
+android.icu.impl.Trie
+android.icu.impl.Trie$DataManipulate
+android.icu.impl.Trie$DefaultGetFoldingOffset
android.icu.impl.Trie2
android.icu.impl.Trie2$1
android.icu.impl.Trie2$Range
@@ -1056,6 +1179,9 @@
android.icu.impl.Trie2$ValueMapper
android.icu.impl.Trie2$ValueWidth
android.icu.impl.Trie2_16
+android.icu.impl.Trie2_32
+android.icu.impl.UBiDiProps
+android.icu.impl.UBiDiProps$IsAcceptable
android.icu.impl.UCharacterProperty
android.icu.impl.UCharacterProperty$1
android.icu.impl.UCharacterProperty$10
@@ -1090,10 +1216,22 @@
android.icu.impl.UCharacterProperty$NormQuickCheckIntProperty
android.icu.impl.UPropertyAliases
android.icu.impl.UPropertyAliases$IsAcceptable
+android.icu.impl.URLHandler$URLVisitor
+android.icu.impl.USerializedSet
android.icu.impl.Utility
android.icu.impl.ZoneMeta
android.icu.impl.ZoneMeta$CustomTimeZoneCache
android.icu.impl.ZoneMeta$SystemTimeZoneCache
+android.icu.impl.coll.CollationData
+android.icu.impl.coll.CollationDataReader
+android.icu.impl.coll.CollationDataReader$IsAcceptable
+android.icu.impl.coll.CollationFastLatin
+android.icu.impl.coll.CollationLoader
+android.icu.impl.coll.CollationRoot
+android.icu.impl.coll.CollationSettings
+android.icu.impl.coll.CollationTailoring
+android.icu.impl.coll.SharedObject
+android.icu.impl.coll.SharedObject$Reference
android.icu.impl.locale.AsciiUtil
android.icu.impl.locale.BaseLocale
android.icu.impl.locale.BaseLocale$Cache
@@ -1106,6 +1244,13 @@
android.icu.lang.UCharacterEnums$ECharacterDirection
android.icu.lang.UScript
android.icu.lang.UScript$ScriptUsage
+android.icu.math.BigDecimal
+android.icu.math.MathContext
+android.icu.text.Collator
+android.icu.text.Collator$ServiceShim
+android.icu.text.CollatorServiceShim
+android.icu.text.CollatorServiceShim$CService
+android.icu.text.CollatorServiceShim$CService$1CollatorFactory
android.icu.text.CurrencyDisplayNames
android.icu.text.CurrencyMetaInfo
android.icu.text.CurrencyMetaInfo$CurrencyDigits
@@ -1129,9 +1274,12 @@
android.icu.text.DateTimePatternGenerator$PatternWithSkeletonFlag
android.icu.text.DateTimePatternGenerator$VariableField
android.icu.text.DecimalFormat
+android.icu.text.DecimalFormat$Unit
android.icu.text.DecimalFormatSymbols
+android.icu.text.DigitList
android.icu.text.DisplayContext
android.icu.text.DisplayContext$Type
+android.icu.text.IDNA
android.icu.text.MessageFormat
android.icu.text.MessageFormat$AppendableWrapper
android.icu.text.MessageFormat$Field
@@ -1140,13 +1288,48 @@
android.icu.text.MessagePattern$ArgType
android.icu.text.MessagePattern$Part
android.icu.text.MessagePattern$Part$Type
+android.icu.text.Normalizer
+android.icu.text.Normalizer$FCDMode
+android.icu.text.Normalizer$Mode
+android.icu.text.Normalizer$ModeImpl
+android.icu.text.Normalizer$NFCMode
+android.icu.text.Normalizer$NFDMode
+android.icu.text.Normalizer$NFKCMode
+android.icu.text.Normalizer$NFKDMode
+android.icu.text.Normalizer$NFKDModeImpl
+android.icu.text.Normalizer$NONEMode
+android.icu.text.Normalizer$QuickCheckResult
+android.icu.text.Normalizer2
android.icu.text.NumberFormat
+android.icu.text.NumberFormat$Field
android.icu.text.NumberingSystem
+android.icu.text.PluralRanges
+android.icu.text.PluralRanges$Matrix
+android.icu.text.PluralRules
+android.icu.text.PluralRules$1
+android.icu.text.PluralRules$AndConstraint
+android.icu.text.PluralRules$BinaryConstraint
+android.icu.text.PluralRules$Constraint
+android.icu.text.PluralRules$Factory
+android.icu.text.PluralRules$FixedDecimal
+android.icu.text.PluralRules$FixedDecimalRange
+android.icu.text.PluralRules$FixedDecimalSamples
+android.icu.text.PluralRules$Operand
+android.icu.text.PluralRules$PluralType
+android.icu.text.PluralRules$RangeConstraint
+android.icu.text.PluralRules$Rule
+android.icu.text.PluralRules$RuleList
+android.icu.text.PluralRules$SampleType
+android.icu.text.PluralRules$SimpleTokenizer
android.icu.text.Replaceable
android.icu.text.ReplaceableString
+android.icu.text.RuleBasedCollator
android.icu.text.SimpleDateFormat
android.icu.text.SimpleDateFormat$PatternItem
+android.icu.text.StringPrep
+android.icu.text.StringPrepParseException
android.icu.text.UCharacterIterator
+android.icu.text.UFieldPosition
android.icu.text.UFormat
android.icu.text.UForwardCharacterIterator
android.icu.text.UTF16
@@ -1166,6 +1349,7 @@
android.icu.util.Calendar$WeekData
android.icu.util.Calendar$WeekDataCache
android.icu.util.Currency
+android.icu.util.Currency$CurrencyUsage
android.icu.util.Currency$EquivalenceRelation
android.icu.util.Freezable
android.icu.util.GregorianCalendar
@@ -1174,6 +1358,7 @@
android.icu.util.MeasureUnit$2
android.icu.util.MeasureUnit$3
android.icu.util.MeasureUnit$Factory
+android.icu.util.Output
android.icu.util.SimpleTimeZone
android.icu.util.TimeUnit
android.icu.util.TimeZone
@@ -1187,16 +1372,27 @@
android.icu.util.UResourceBundleIterator
android.icu.util.UResourceTypeMismatchException
android.icu.util.VersionInfo
-android.inputmethodservice.ExtractEditText
android.location.CountryDetector
+android.location.GnssMeasurementCallbackTransport
+android.location.GnssMeasurementCallbackTransport$ListenerTransport
+android.location.GnssNavigationMessageCallbackTransport
+android.location.GnssNavigationMessageCallbackTransport$ListenerTransport
+android.location.IGnssMeasurementsListener
+android.location.IGnssMeasurementsListener$Stub
+android.location.IGnssNavigationMessageListener
+android.location.IGnssNavigationMessageListener$Stub
+android.location.ILocationManager
+android.location.ILocationManager$Stub
+android.location.ILocationManager$Stub$Proxy
+android.location.LocalListenerHelper
android.location.Location
android.location.Location$1
+android.location.Location$2
android.location.LocationManager
android.media.AmrInputStream
android.media.AudioAttributes
android.media.AudioAttributes$1
android.media.AudioAttributes$Builder
-android.media.AudioDeviceInfo
android.media.AudioDevicePort
android.media.AudioDevicePortConfig
android.media.AudioFormat
@@ -1205,31 +1401,45 @@
android.media.AudioHandle
android.media.AudioManager
android.media.AudioManager$1
-android.media.AudioManager$FocusEventHandlerDelegate
-android.media.AudioManager$FocusEventHandlerDelegate$1
-android.media.AudioManager$OnAmPortUpdateListener
-android.media.AudioManager$OnAudioPortUpdateListener
+android.media.AudioManager$2
+android.media.AudioManager$OnAudioFocusChangeListener
+android.media.AudioManager$ServiceEventHandlerDelegate
+android.media.AudioManager$ServiceEventHandlerDelegate$1
android.media.AudioMixPort
android.media.AudioMixPortConfig
android.media.AudioPatch
android.media.AudioPort
android.media.AudioPortConfig
android.media.AudioPortEventHandler
-android.media.AudioPortEventHandler$1
android.media.AudioRecord
+android.media.AudioRoutesInfo
+android.media.AudioRoutesInfo$1
+android.media.AudioRouting
android.media.AudioSystem
+android.media.AudioTimestamp
android.media.AudioTrack
android.media.CamcorderProfile
android.media.CameraProfile
android.media.DecoderCapabilities
android.media.EncoderCapabilities
+android.media.ExifInterface
android.media.IAudioFocusDispatcher
android.media.IAudioFocusDispatcher$Stub
+android.media.IAudioRoutesObserver
+android.media.IAudioRoutesObserver$Stub
android.media.IAudioService
android.media.IAudioService$Stub
android.media.IAudioService$Stub$Proxy
android.media.IMediaHTTPConnection
android.media.IMediaHTTPConnection$Stub
+android.media.IMediaRouterClient
+android.media.IMediaRouterClient$Stub
+android.media.IMediaRouterService
+android.media.IMediaRouterService$Stub
+android.media.IRecordingConfigDispatcher
+android.media.IRecordingConfigDispatcher$Stub
+android.media.IRemoteVolumeObserver
+android.media.IRemoteVolumeObserver$Stub
android.media.Image
android.media.ImageReader
android.media.ImageReader$SurfaceImage
@@ -1245,37 +1455,46 @@
android.media.MediaMetadataRetriever
android.media.MediaMuxer
android.media.MediaPlayer
-android.media.MediaPlayer$1
-android.media.MediaPlayer$EventHandler
android.media.MediaPlayer$OnCompletionListener
android.media.MediaPlayer$OnErrorListener
+android.media.MediaPlayer$OnPreparedListener
android.media.MediaPlayer$OnSeekCompleteListener
-android.media.MediaPlayer$OnSubtitleDataListener
-android.media.MediaPlayer$TimeProvider
-android.media.MediaPlayer$TimeProvider$EventHandler
android.media.MediaRecorder
android.media.MediaRouter
+android.media.MediaRouter$Callback
+android.media.MediaRouter$RouteCategory
+android.media.MediaRouter$RouteInfo
+android.media.MediaRouter$RouteInfo$1
+android.media.MediaRouter$Static
+android.media.MediaRouter$Static$1
+android.media.MediaRouter$Static$Client
+android.media.MediaRouter$VolumeChangeReceiver
+android.media.MediaRouter$WifiDisplayStatusChangedReceiver
+android.media.MediaRouterClientState
+android.media.MediaRouterClientState$1
android.media.MediaScanner
android.media.MediaSync
-android.media.MediaTimeProvider
-android.media.MediaTimeProvider$OnMediaTimeListener
android.media.PlaybackParams
android.media.PlaybackParams$1
android.media.RemoteDisplay
android.media.ResampleInputStream
android.media.SubtitleController$Listener
-android.media.SyncParams
+android.media.ThumbnailUtils
android.media.ToneGenerator
+android.media.audiofx.AcousticEchoCanceler
+android.media.audiofx.AudioEffect
android.media.audiopolicy.AudioMix
android.media.audiopolicy.AudioMixingRule
-android.media.audiopolicy.AudioMixingRule$AttributeMatchCriterion
+android.media.audiopolicy.AudioMixingRule$AudioMixMatchCriterion
android.media.midi.MidiManager
android.media.projection.MediaProjectionManager
android.media.session.MediaSessionManager
+android.media.soundtrigger.SoundTriggerManager
android.media.tv.TvInputManager
android.mtp.MtpDatabase
android.mtp.MtpDevice
android.mtp.MtpDeviceInfo
+android.mtp.MtpEvent
android.mtp.MtpObjectInfo
android.mtp.MtpPropertyGroup
android.mtp.MtpPropertyList
@@ -1283,6 +1502,8 @@
android.mtp.MtpStorage
android.mtp.MtpStorageInfo
android.net.ConnectivityManager
+android.net.ConnectivityManager$CallbackHandler
+android.net.ConnectivityManager$NetworkCallback
android.net.Credentials
android.net.DhcpResults
android.net.DhcpResults$1
@@ -1301,18 +1522,24 @@
android.net.LocalSocketImpl
android.net.LocalSocketImpl$SocketInputStream
android.net.LocalSocketImpl$SocketOutputStream
+android.net.Network
+android.net.Network$1
+android.net.NetworkCapabilities
+android.net.NetworkCapabilities$1
android.net.NetworkInfo
android.net.NetworkInfo$1
android.net.NetworkInfo$DetailedState
android.net.NetworkInfo$State
android.net.NetworkPolicyManager
+android.net.NetworkRequest
+android.net.NetworkRequest$1
+android.net.NetworkRequest$Builder
android.net.NetworkScoreManager
android.net.NetworkStats
android.net.NetworkStats$1
android.net.NetworkUtils
android.net.Proxy
android.net.ProxyInfo
-android.net.ProxyInfo$1
android.net.RouteInfo
android.net.RouteInfo$1
android.net.SSLCertificateSocketFactory
@@ -1334,8 +1561,6 @@
android.net.Uri$PathSegments
android.net.Uri$PathSegmentsBuilder
android.net.Uri$StringUri
-android.net.http.AndroidHttpClient
-android.net.http.AndroidHttpClient$1
android.net.nsd.NsdManager
android.net.wifi.IWifiManager
android.net.wifi.IWifiManager$Stub
@@ -1346,13 +1571,12 @@
android.net.wifi.WifiInfo
android.net.wifi.WifiInfo$1
android.net.wifi.WifiManager
-android.net.wifi.WifiManager$ServiceHandler
android.net.wifi.WifiManager$WifiLock
android.net.wifi.WifiScanner
android.net.wifi.WifiSsid
android.net.wifi.WifiSsid$1
+android.net.wifi.nan.WifiNanManager
android.net.wifi.p2p.WifiP2pManager
-android.net.wifi.passpoint.WifiPasspointManager
android.nfc.IAppCallback
android.nfc.IAppCallback$Stub
android.nfc.INfcAdapter
@@ -1360,13 +1584,10 @@
android.nfc.INfcAdapter$Stub$Proxy
android.nfc.INfcCardEmulation
android.nfc.INfcCardEmulation$Stub
-android.nfc.INfcCardEmulation$Stub$Proxy
+android.nfc.INfcFCardEmulation
+android.nfc.INfcFCardEmulation$Stub
android.nfc.INfcTag
android.nfc.INfcTag$Stub
-android.nfc.INfcTag$Stub$Proxy
-android.nfc.NfcActivityManager
-android.nfc.NfcAdapter
-android.nfc.NfcAdapter$1
android.nfc.NfcManager
android.opengl.EGL14
android.opengl.EGLConfig
@@ -1384,6 +1605,7 @@
android.opengl.GLES30
android.opengl.GLES31
android.opengl.GLES31Ext
+android.opengl.GLES32
android.opengl.GLUtils
android.opengl.Matrix
android.opengl.Visibility
@@ -1408,6 +1630,9 @@
android.os.CancellationSignal
android.os.CancellationSignal$OnCancelListener
android.os.CancellationSignal$Transport
+android.os.ConditionVariable
+android.os.CpuUsageInfo
+android.os.CpuUsageInfo$1
android.os.DeadObjectException
android.os.Debug
android.os.Debug$MemoryInfo
@@ -1421,6 +1646,7 @@
android.os.Handler$Callback
android.os.Handler$MessengerImpl
android.os.HandlerThread
+android.os.HardwarePropertiesManager
android.os.IBinder
android.os.IBinder$DeathRecipient
android.os.ICancellationSignal
@@ -1447,16 +1673,16 @@
android.os.MessageQueue$IdleHandler
android.os.Messenger
android.os.Messenger$1
+android.os.OperationCanceledException
android.os.Parcel
android.os.Parcel$1
android.os.ParcelFileDescriptor
android.os.ParcelFileDescriptor$1
android.os.ParcelFileDescriptor$AutoCloseInputStream
+android.os.ParcelUuid
android.os.Parcelable
android.os.Parcelable$ClassLoaderCreator
android.os.Parcelable$Creator
-android.os.ParcelableParcel
-android.os.ParcelableParcel$1
android.os.PatternMatcher
android.os.PatternMatcher$1
android.os.PersistableBundle
@@ -1466,6 +1692,7 @@
android.os.PowerManager$WakeLock$1
android.os.Process
android.os.RemoteException
+android.os.ResultReceiver
android.os.SELinux
android.os.ServiceManager
android.os.ServiceManagerNative
@@ -1492,6 +1719,7 @@
android.os.StrictMode$StrictModeDiskWriteViolation
android.os.StrictMode$StrictModeViolation
android.os.StrictMode$ThreadPolicy
+android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState
android.os.StrictMode$ViolationInfo
android.os.StrictMode$VmPolicy
@@ -1500,6 +1728,7 @@
android.os.SystemProperties
android.os.Trace
android.os.Trace$1
+android.os.TransactionTooLargeException
android.os.UEventObserver
android.os.UserHandle
android.os.UserHandle$1
@@ -1512,7 +1741,9 @@
android.os.storage.StorageManager
android.os.storage.StorageVolume
android.os.storage.StorageVolume$1
+android.preference.Preference$OnPreferenceChangeListener
android.preference.PreferenceActivity
+android.preference.PreferenceFragment
android.preference.PreferenceFragment$OnPreferenceStartFragmentCallback
android.preference.PreferenceManager
android.preference.PreferenceManager$OnPreferenceTreeClickListener
@@ -1556,17 +1787,33 @@
android.provider.Settings$System$InclusiveIntegerRangeValidator
android.provider.Settings$System$Validator
android.renderscript.RenderScriptCacheDir
-android.security.IKeystoreService
-android.security.IKeystoreService$Stub
-android.security.IKeystoreService$Stub$Proxy
-android.security.KeyStore
-android.security.KeyStoreException
+android.security.FrameworkNetworkSecurityPolicy
+android.security.KeyChain
android.security.NetworkSecurityPolicy
android.security.keystore.AndroidKeyStoreBCWorkaroundProvider
-android.security.keystore.AndroidKeyStoreKey
android.security.keystore.AndroidKeyStoreProvider
-android.security.keystore.KeyStoreCryptoOperation
+android.security.net.config.ApplicationConfig
+android.security.net.config.CertificateSource
+android.security.net.config.CertificatesEntryRef
+android.security.net.config.ConfigNetworkSecurityPolicy
+android.security.net.config.ConfigSource
+android.security.net.config.DirectoryCertificateSource
+android.security.net.config.DirectoryCertificateSource$1
+android.security.net.config.DirectoryCertificateSource$3
+android.security.net.config.DirectoryCertificateSource$CertSelector
+android.security.net.config.ManifestConfigSource
+android.security.net.config.ManifestConfigSource$DefaultConfigSource
+android.security.net.config.NetworkSecurityConfig
+android.security.net.config.NetworkSecurityConfig$1
+android.security.net.config.NetworkSecurityConfig$Builder
android.security.net.config.NetworkSecurityConfigProvider
+android.security.net.config.NetworkSecurityTrustManager
+android.security.net.config.PinSet
+android.security.net.config.RootTrustManager
+android.security.net.config.RootTrustManagerFactorySpi
+android.security.net.config.SystemCertificateSource
+android.security.net.config.TrustedCertificateStoreAdapter
+android.security.net.config.UserCertificateSource
android.service.persistentdata.PersistentDataBlockManager
android.system.ErrnoException
android.system.GaiException
@@ -1586,6 +1833,7 @@
android.system.StructTimeval
android.system.StructUcred
android.system.StructUtsname
+android.system.UnixSocketAddress
android.telecom.TelecomManager
android.telephony.CarrierConfigManager
android.telephony.PhoneNumberUtils
@@ -1604,15 +1852,12 @@
android.text.GetChars
android.text.GraphicsOperations
android.text.Html
-android.text.Html$HtmlParser
-android.text.HtmlToSpannedConverter
android.text.Hyphenator
android.text.InputFilter
android.text.InputType
android.text.Layout
android.text.Layout$Alignment
android.text.Layout$Directions
-android.text.Layout$Ellipsizer
android.text.MeasuredText
android.text.NoCopySpan
android.text.NoCopySpan$Concrete
@@ -1647,6 +1892,8 @@
android.text.TextUtils
android.text.TextUtils$1
android.text.TextUtils$EllipsizeCallback
+android.text.TextUtils$SimpleStringSplitter
+android.text.TextUtils$StringSplitter
android.text.TextUtils$TruncateAt
android.text.TextWatcher
android.text.format.DateFormat
@@ -1669,13 +1916,17 @@
android.text.method.SingleLineTransformationMethod
android.text.method.TextKeyListener
android.text.method.TextKeyListener$Capitalize
+android.text.method.Touch
android.text.method.TransformationMethod
android.text.method.TransformationMethod2
android.text.style.AlignmentSpan
+android.text.style.BackgroundColorSpan
android.text.style.CharacterStyle
android.text.style.ClickableSpan
+android.text.style.DynamicDrawableSpan
android.text.style.EasyEditSpan
android.text.style.ForegroundColorSpan
+android.text.style.ImageSpan
android.text.style.LeadingMarginSpan
android.text.style.LineBackgroundSpan
android.text.style.LineHeightSpan
@@ -1687,6 +1938,7 @@
android.text.style.SuggestionSpan
android.text.style.TabStopSpan
android.text.style.URLSpan
+android.text.style.UnderlineSpan
android.text.style.UpdateAppearance
android.text.style.UpdateLayout
android.text.style.WrapTogetherSpan
@@ -1710,6 +1962,7 @@
android.transition.Scene
android.transition.Transition
android.transition.Transition$1
+android.transition.Transition$EpicenterCallback
android.transition.TransitionInflater
android.transition.TransitionManager
android.transition.TransitionSet
@@ -1720,6 +1973,7 @@
android.util.ArrayMap
android.util.ArrayMap$1
android.util.ArraySet
+android.util.ArraySet$1
android.util.AttributeSet
android.util.Base64
android.util.Base64$Coder
@@ -1731,38 +1985,44 @@
android.util.EventLog$Event
android.util.FloatProperty
android.util.IntProperty
+android.util.JsonReader
+android.util.LocaleList
+android.util.LocaleList$1
android.util.Log
android.util.Log$1
+android.util.Log$ImmediateLogWriter
android.util.Log$TerribleFailureHandler
+android.util.LogPrinter
+android.util.LongArray
android.util.LongSparseArray
android.util.LongSparseLongArray
android.util.LruCache
android.util.MapCollections
android.util.MapCollections$ArrayIterator
android.util.MapCollections$KeySet
-android.util.MapCollections$ValuesCollection
android.util.MathUtils
android.util.MutableInt
android.util.MutableLong
android.util.Pair
android.util.PathParser
-android.util.PathParser$ExtractFloatResult
-android.util.PathParser$PathDataNode
+android.util.PathParser$PathData
android.util.Patterns
android.util.Pools$Pool
android.util.Pools$SimplePool
android.util.Pools$SynchronizedPool
android.util.Printer
android.util.Property
+android.util.Rational
android.util.Singleton
android.util.Size
-android.util.SizeF
android.util.Slog
android.util.SparseArray
android.util.SparseBooleanArray
android.util.SparseIntArray
+android.util.SparseLongArray
android.util.StateSet
android.util.SuperNotCalledException
+android.util.TimeFormatException
android.util.TypedValue
android.util.Xml
android.util.jar.StrictJarFile
@@ -1785,6 +2045,8 @@
android.view.ContextMenu$ContextMenuInfo
android.view.ContextThemeWrapper
android.view.Display
+android.view.Display$ColorTransform
+android.view.Display$ColorTransform$1
android.view.Display$Mode
android.view.Display$Mode$1
android.view.DisplayAdjustments
@@ -1792,11 +2054,14 @@
android.view.DisplayInfo
android.view.DisplayInfo$1
android.view.DisplayListCanvas
+android.view.DragEvent
android.view.FallbackEventHandler
android.view.FocusFinder
android.view.FocusFinder$1
android.view.FocusFinder$SequentialFocusComparator
android.view.FrameInfo
+android.view.FrameMetrics
+android.view.FrameMetricsObserver
android.view.FrameStats
android.view.GestureDetector
android.view.GestureDetector$GestureHandler
@@ -1807,9 +2072,9 @@
android.view.GraphicBuffer
android.view.GraphicBuffer$1
android.view.Gravity
+android.view.HandlerActionQueue
+android.view.HandlerActionQueue$HandlerAction
android.view.HardwareLayer
-android.view.HardwareRenderer
-android.view.HardwareRenderer$HardwareDrawCallbacks
android.view.IAssetAtlas
android.view.IAssetAtlas$Stub
android.view.IAssetAtlas$Stub$Proxy
@@ -1833,6 +2098,7 @@
android.view.InputChannel$1
android.view.InputDevice
android.view.InputDevice$1
+android.view.InputDevice$MotionRange
android.view.InputEvent
android.view.InputEvent$1
android.view.InputEventConsistencyVerifier
@@ -1844,6 +2110,7 @@
android.view.KeyCharacterMap
android.view.KeyCharacterMap$1
android.view.KeyCharacterMap$FallbackAction
+android.view.KeyCharacterMap$KeyData
android.view.KeyEvent
android.view.KeyEvent$1
android.view.KeyEvent$Callback
@@ -1868,7 +2135,9 @@
android.view.RenderNode
android.view.RenderNodeAnimator
android.view.RenderNodeAnimator$1
+android.view.RenderNodeAnimatorSetHelper
android.view.SearchEvent
+android.view.SoundEffectConstants
android.view.SubMenu
android.view.Surface
android.view.Surface$1
@@ -1876,11 +2145,14 @@
android.view.Surface$OutOfResourcesException
android.view.SurfaceControl
android.view.SurfaceControl$PhysicalDisplayInfo
+android.view.SurfaceHolder
android.view.SurfaceHolder$Callback
android.view.SurfaceHolder$Callback2
android.view.SurfaceSession
+android.view.SurfaceView
android.view.TextureView
android.view.ThreadedRenderer
+android.view.ThreadedRenderer$HardwareDrawCallbacks
android.view.ThreadedRenderer$ProcessInitializer
android.view.VelocityTracker
android.view.VelocityTracker$Estimator
@@ -1954,8 +2226,6 @@
android.view.ViewRootImpl$NativePostImeInputStage
android.view.ViewRootImpl$NativePreImeInputStage
android.view.ViewRootImpl$QueuedInputEvent
-android.view.ViewRootImpl$RunQueue
-android.view.ViewRootImpl$RunQueue$HandlerAction
android.view.ViewRootImpl$SyntheticInputStage
android.view.ViewRootImpl$SyntheticJoystickHandler
android.view.ViewRootImpl$SyntheticKeyboardHandler
@@ -1982,10 +2252,13 @@
android.view.Window
android.view.Window$Callback
android.view.Window$OnWindowDismissedCallback
+android.view.Window$WindowControllerCallback
android.view.WindowAnimationFrameStats
android.view.WindowAnimationFrameStats$1
+android.view.WindowCallbacks
android.view.WindowContentFrameStats
android.view.WindowContentFrameStats$1
+android.view.WindowId
android.view.WindowInsets
android.view.WindowLeaked
android.view.WindowManager
@@ -2006,6 +2279,9 @@
android.view.accessibility.AccessibilityNodeProvider
android.view.accessibility.AccessibilityRecord
android.view.accessibility.CaptioningManager
+android.view.accessibility.CaptioningManager$1
+android.view.accessibility.CaptioningManager$CaptioningChangeListener
+android.view.accessibility.CaptioningManager$MyContentObserver
android.view.accessibility.IAccessibilityManager
android.view.accessibility.IAccessibilityManager$Stub
android.view.accessibility.IAccessibilityManager$Stub$Proxy
@@ -2019,12 +2295,15 @@
android.view.animation.Animation$2
android.view.animation.Animation$3
android.view.animation.Animation$AnimationListener
+android.view.animation.AnimationSet
android.view.animation.AnimationUtils
android.view.animation.BaseInterpolator
android.view.animation.DecelerateInterpolator
android.view.animation.Interpolator
android.view.animation.LinearInterpolator
+android.view.animation.OvershootInterpolator
android.view.animation.PathInterpolator
+android.view.animation.ScaleAnimation
android.view.animation.Transformation
android.view.animation.TranslateAnimation
android.view.inputmethod.BaseInputConnection
@@ -2044,12 +2323,14 @@
android.view.inputmethod.InputMethodManager$H
android.view.inputmethod.InputMethodManager$ImeInputEventSender
android.view.inputmethod.InputMethodManager$PendingEvent
+android.view.inputmethod.InputMethodSubtype
android.view.textservice.SpellCheckerSession$SpellCheckerSessionListener
android.view.textservice.SpellCheckerSubtype
android.view.textservice.SpellCheckerSubtype$1
android.view.textservice.TextServicesManager
-android.webkit.IWebViewUpdateService
-android.webkit.IWebViewUpdateService$Stub
+android.webkit.MimeTypeMap
+android.webkit.URLUtil
+android.webkit.WebSettings
android.webkit.WebView
android.webkit.WebViewFactory
android.webkit.WebViewFactory$MissingWebViewPackageException
@@ -2065,8 +2346,8 @@
android.widget.AbsListView$SavedState$1
android.widget.AbsListView$SelectionBoundsAdjuster
android.widget.AbsListView$WindowRunnnable
+android.widget.AbsSeekBar
android.widget.AbsSpinner
-android.widget.AbsSpinner$RecycleBin
android.widget.AbsoluteLayout
android.widget.ActionMenuPresenter
android.widget.ActionMenuPresenter$1
@@ -2076,17 +2357,23 @@
android.widget.ActionMenuPresenter$PopupPresenterCallback
android.widget.ActionMenuView
android.widget.ActionMenuView$ActionMenuChildView
-android.widget.ActionMenuView$LayoutParams
android.widget.ActionMenuView$OnMenuItemClickListener
android.widget.Adapter
android.widget.AdapterView
android.widget.AdapterView$AdapterDataSetObserver
android.widget.AdapterView$OnItemClickListener
+android.widget.AdapterView$OnItemLongClickListener
android.widget.AdapterView$OnItemSelectedListener
android.widget.ArrayAdapter
+android.widget.AutoCompleteTextView
+android.widget.AutoCompleteTextView$DropDownItemClickListener
+android.widget.AutoCompleteTextView$MyWatcher
+android.widget.AutoCompleteTextView$PassThroughClickListener
android.widget.BaseAdapter
android.widget.Button
+android.widget.CheckBox
android.widget.Checkable
+android.widget.CheckedTextView
android.widget.CompoundButton
android.widget.CompoundButton$OnCheckedChangeListener
android.widget.EdgeEffect
@@ -2094,6 +2381,7 @@
android.widget.Editor
android.widget.Editor$1
android.widget.Editor$2
+android.widget.Editor$3
android.widget.Editor$Blink
android.widget.Editor$CursorAnchorInfoNotifier
android.widget.Editor$EditOperation
@@ -2101,17 +2389,23 @@
android.widget.Editor$InputContentType
android.widget.Editor$InputMethodState
android.widget.Editor$PositionListener
+android.widget.Editor$ProcessTextIntentActionsHandler
android.widget.Editor$SpanController
+android.widget.Editor$SuggestionHelper
+android.widget.Editor$SuggestionHelper$SuggestionSpanComparator
android.widget.Editor$TextRenderNode
android.widget.Editor$TextViewPositionListener
android.widget.Editor$UndoInputFilter
android.widget.Filter
android.widget.Filter$FilterListener
android.widget.Filterable
+android.widget.ForwardingListener
android.widget.FrameLayout
android.widget.FrameLayout$LayoutParams
android.widget.HeaderViewListAdapter
android.widget.HorizontalScrollView
+android.widget.HorizontalScrollView$SavedState
+android.widget.HorizontalScrollView$SavedState$1
android.widget.ImageButton
android.widget.ImageView
android.widget.ImageView$ScaleType
@@ -2119,7 +2413,6 @@
android.widget.LinearLayout$LayoutParams
android.widget.ListAdapter
android.widget.ListPopupWindow
-android.widget.ListPopupWindow$ForwardingListener
android.widget.ListPopupWindow$ListSelectorHider
android.widget.ListPopupWindow$PopupDataSetObserver
android.widget.ListPopupWindow$PopupScrollListener
@@ -2128,48 +2421,38 @@
android.widget.ListView
android.widget.ListView$ArrowScrollFocusResult
android.widget.ListView$FixedViewInfo
+android.widget.MultiAutoCompleteTextView
android.widget.OverScroller
android.widget.OverScroller$SplineOverScroller
android.widget.PopupWindow
android.widget.PopupWindow$1
+android.widget.PopupWindow$2
android.widget.PopupWindow$OnDismissListener
android.widget.ProgressBar
+android.widget.ProgressBar$1
android.widget.ProgressBar$SavedState
android.widget.ProgressBar$SavedState$1
+android.widget.RadioButton
+android.widget.RatingBar
android.widget.RelativeLayout
android.widget.RelativeLayout$DependencyGraph
android.widget.RelativeLayout$DependencyGraph$Node
android.widget.RelativeLayout$LayoutParams
android.widget.RemoteViews
-android.widget.RemoteViews$1
-android.widget.RemoteViews$2
-android.widget.RemoteViews$Action
-android.widget.RemoteViews$ActionException
-android.widget.RemoteViews$BitmapCache
-android.widget.RemoteViews$MemoryUsageCounter
-android.widget.RemoteViews$MutablePair
-android.widget.RemoteViews$OnClickHandler
-android.widget.RemoteViews$ReflectionAction
-android.widget.RemoteViews$SetDrawableParameters
-android.widget.RemoteViews$TextViewSizeAction
-android.widget.RemoteViews$ViewPaddingAction
android.widget.RemoteViewsAdapter$RemoteAdapterConnectionCallback
android.widget.RtlSpacingHelper
android.widget.ScrollBarDrawable
android.widget.ScrollView
-android.widget.ScrollView$SavedState
-android.widget.ScrollView$SavedState$1
android.widget.Scroller
android.widget.Scroller$ViscousFluidInterpolator
android.widget.SectionIndexer
+android.widget.SeekBar
android.widget.Space
android.widget.SpellChecker
android.widget.SpellChecker$SpellParser
android.widget.Spinner
-android.widget.Spinner$SpinnerPopup
android.widget.SpinnerAdapter
android.widget.TextView
-android.widget.TextView$2
android.widget.TextView$3
android.widget.TextView$BufferType
android.widget.TextView$ChangeWatcher
@@ -2177,13 +2460,17 @@
android.widget.TextView$Drawables
android.widget.TextView$OnEditorActionListener
android.widget.TextView$SavedState
-android.widget.TextView$SavedState$1
android.widget.ThemedSpinnerAdapter
+android.widget.Toast
+android.widget.Toast$TN
+android.widget.Toast$TN$1
+android.widget.Toast$TN$2
android.widget.Toolbar
android.widget.Toolbar$1
android.widget.Toolbar$2
android.widget.Toolbar$ExpandedActionViewMenuPresenter
android.widget.Toolbar$LayoutParams
+android.widget.ViewAnimator
android.widget.WrapperListAdapter
com.android.dex.Annotation
com.android.dex.ClassData
@@ -2216,19 +2503,10 @@
com.android.dex.util.ByteOutput
com.android.dex.util.ExceptionWithContext
com.android.dex.util.FileUtils
-com.android.i18n.phonenumbers.CountryCodeToRegionCodeMap
-com.android.i18n.phonenumbers.MetadataLoader
com.android.i18n.phonenumbers.NumberParseException
-com.android.i18n.phonenumbers.PhoneNumberUtil
-com.android.i18n.phonenumbers.PhoneNumberUtil$1
-com.android.i18n.phonenumbers.RegexCache
-com.android.i18n.phonenumbers.RegexCache$LRUCache
-com.android.i18n.phonenumbers.RegexCache$LRUCache$1
com.android.internal.R$styleable
com.android.internal.app.AlertController
com.android.internal.app.AlertController$1
-com.android.internal.app.AlertController$2
-com.android.internal.app.AlertController$AlertParams
com.android.internal.app.AlertController$ButtonHandler
com.android.internal.app.IAppOpsService
com.android.internal.app.IAppOpsService$Stub
@@ -2236,15 +2514,13 @@
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
com.android.internal.app.WindowDecorActionBar
-com.android.internal.app.WindowDecorActionBar$1
-com.android.internal.app.WindowDecorActionBar$2
-com.android.internal.app.WindowDecorActionBar$3
com.android.internal.appwidget.IAppWidgetService
com.android.internal.appwidget.IAppWidgetService$Stub
com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
com.android.internal.content.NativeLibraryHelper
com.android.internal.content.ReferrerIntent
com.android.internal.content.ReferrerIntent$1
+com.android.internal.inputmethod.InputMethodUtils
com.android.internal.logging.AndroidConfig
com.android.internal.logging.AndroidHandler
com.android.internal.logging.AndroidHandler$1
@@ -2252,6 +2528,7 @@
com.android.internal.os.AndroidPrintStream
com.android.internal.os.BinderInternal
com.android.internal.os.BinderInternal$GcWatcher
+com.android.internal.os.InstallerConnection$InstallerException
com.android.internal.os.LoggingPrintStream
com.android.internal.os.LoggingPrintStream$1
com.android.internal.os.RuntimeInit
@@ -2266,17 +2543,15 @@
com.android.internal.os.ZygoteInit
com.android.internal.os.ZygoteInit$MethodAndArgsCaller
com.android.internal.os.ZygoteSecurityException
+com.android.internal.policy.DecorContext
+com.android.internal.policy.DecorView
+com.android.internal.policy.DecorView$ColorViewState
com.android.internal.policy.PhoneFallbackEventHandler
com.android.internal.policy.PhoneLayoutInflater
com.android.internal.policy.PhoneWindow
com.android.internal.policy.PhoneWindow$1
-com.android.internal.policy.PhoneWindow$ActionMenuPresenterCallback
-com.android.internal.policy.PhoneWindow$ColorViewState
-com.android.internal.policy.PhoneWindow$DecorView
-com.android.internal.policy.PhoneWindow$DialogMenuCallback
com.android.internal.policy.PhoneWindow$PanelFeatureState
-com.android.internal.policy.PhoneWindow$PanelFeatureState$SavedState
-com.android.internal.policy.PhoneWindow$PanelFeatureState$SavedState$1
+com.android.internal.policy.PhoneWindow$PhoneWindowMenuCallback
com.android.internal.policy.PhoneWindow$RotationWatcher
com.android.internal.policy.PhoneWindow$RotationWatcher$1
com.android.internal.telephony.ISub
@@ -2295,13 +2570,11 @@
com.android.internal.transition.EpicenterTranslateClipReveal
com.android.internal.transition.TransitionConstants
com.android.internal.util.ArrayUtils
-com.android.internal.util.AsyncChannel
-com.android.internal.util.AsyncChannel$DeathMonitor
-com.android.internal.util.FastMath
com.android.internal.util.FastPrintWriter
com.android.internal.util.FastPrintWriter$DummyWriter
com.android.internal.util.FastXmlSerializer
com.android.internal.util.GrowingArrayUtils
+com.android.internal.util.LineBreakBufferedWriter
com.android.internal.util.Preconditions
com.android.internal.util.VirtualRefBasePtr
com.android.internal.util.XmlUtils
@@ -2339,25 +2612,16 @@
com.android.internal.view.menu.MenuPresenter
com.android.internal.view.menu.MenuPresenter$Callback
com.android.internal.view.menu.MenuView
-com.android.internal.widget.AbsActionBarView
-com.android.internal.widget.AbsActionBarView$VisibilityAnimListener
-com.android.internal.widget.ActionBarContainer
-com.android.internal.widget.ActionBarContainer$ActionBarBackgroundDrawable
-com.android.internal.widget.ActionBarContextView
-com.android.internal.widget.ActionBarOverlayLayout
-com.android.internal.widget.ActionBarOverlayLayout$1
-com.android.internal.widget.ActionBarOverlayLayout$2
-com.android.internal.widget.ActionBarOverlayLayout$3
-com.android.internal.widget.ActionBarOverlayLayout$4
-com.android.internal.widget.ActionBarOverlayLayout$5
+com.android.internal.view.menu.ShowableListMenu
com.android.internal.widget.ActionBarOverlayLayout$ActionBarVisibilityCallback
-com.android.internal.widget.ActionBarOverlayLayout$LayoutParams
+com.android.internal.widget.AlertDialogLayout
com.android.internal.widget.BackgroundFallback
com.android.internal.widget.ButtonBarLayout
com.android.internal.widget.DecorContentParent
com.android.internal.widget.DecorToolbar
com.android.internal.widget.DialogTitle
com.android.internal.widget.EditableInputConnection
+com.android.internal.widget.ScrollBarUtils
com.android.internal.widget.ToolbarWidgetWrapper
com.android.internal.widget.ToolbarWidgetWrapper$1
com.android.okhttp.Address
@@ -2379,6 +2643,10 @@
com.android.okhttp.Headers
com.android.okhttp.Headers$Builder
com.android.okhttp.HttpHandler
+com.android.okhttp.HttpHandler$CleartextURLFilter
+com.android.okhttp.HttpUrl
+com.android.okhttp.HttpUrl$Builder
+com.android.okhttp.HttpUrl$Builder$ParseResult
com.android.okhttp.HttpsHandler
com.android.okhttp.OkHttpClient
com.android.okhttp.OkHttpClient$1
@@ -2400,6 +2668,7 @@
com.android.okhttp.internal.OptionalMethod
com.android.okhttp.internal.Platform
com.android.okhttp.internal.RouteDatabase
+com.android.okhttp.internal.URLFilter
com.android.okhttp.internal.Util
com.android.okhttp.internal.Util$1
com.android.okhttp.internal.http.AuthenticatorAdapter
@@ -2421,8 +2690,6 @@
com.android.okhttp.internal.http.RetryableSink
com.android.okhttp.internal.http.RouteException
com.android.okhttp.internal.http.RouteSelector
-com.android.okhttp.internal.http.SocketConnector
-com.android.okhttp.internal.http.SocketConnector$ConnectedSocket
com.android.okhttp.internal.http.StatusLine
com.android.okhttp.internal.http.Transport
com.android.okhttp.internal.huc.DelegatingHttpsURLConnection
@@ -2436,6 +2703,7 @@
com.android.okhttp.okio.Buffer
com.android.okhttp.okio.BufferedSink
com.android.okhttp.okio.BufferedSource
+com.android.okhttp.okio.ForwardingTimeout
com.android.okhttp.okio.Okio
com.android.okhttp.okio.Okio$1
com.android.okhttp.okio.Okio$2
@@ -2451,75 +2719,20 @@
com.android.okhttp.okio.Timeout
com.android.okhttp.okio.Timeout$1
com.android.okhttp.okio.Util
-com.android.org.bouncycastle.asn1.ASN1Boolean
-com.android.org.bouncycastle.asn1.ASN1Choice
com.android.org.bouncycastle.asn1.ASN1Encodable
-com.android.org.bouncycastle.asn1.ASN1EncodableVector
-com.android.org.bouncycastle.asn1.ASN1InputStream
-com.android.org.bouncycastle.asn1.ASN1Integer
-com.android.org.bouncycastle.asn1.ASN1Null
com.android.org.bouncycastle.asn1.ASN1Object
com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier
-com.android.org.bouncycastle.asn1.ASN1OctetString
-com.android.org.bouncycastle.asn1.ASN1OctetStringParser
-com.android.org.bouncycastle.asn1.ASN1OutputStream
+com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier$OidHandle
com.android.org.bouncycastle.asn1.ASN1Primitive
-com.android.org.bouncycastle.asn1.ASN1Sequence
-com.android.org.bouncycastle.asn1.ASN1SequenceParser
-com.android.org.bouncycastle.asn1.ASN1Set
-com.android.org.bouncycastle.asn1.ASN1StreamParser
-com.android.org.bouncycastle.asn1.ASN1String
-com.android.org.bouncycastle.asn1.ASN1TaggedObject
-com.android.org.bouncycastle.asn1.ASN1TaggedObjectParser
-com.android.org.bouncycastle.asn1.BERTags
-com.android.org.bouncycastle.asn1.DERBitString
-com.android.org.bouncycastle.asn1.DERFactory
-com.android.org.bouncycastle.asn1.DERIA5String
-com.android.org.bouncycastle.asn1.DERNull
-com.android.org.bouncycastle.asn1.DEROctetString
-com.android.org.bouncycastle.asn1.DEROutputStream
-com.android.org.bouncycastle.asn1.DERPrintableString
-com.android.org.bouncycastle.asn1.DERSequence
-com.android.org.bouncycastle.asn1.DERSet
-com.android.org.bouncycastle.asn1.DERTaggedObject
-com.android.org.bouncycastle.asn1.DERUTF8String
-com.android.org.bouncycastle.asn1.DLSequence
-com.android.org.bouncycastle.asn1.DLSet
-com.android.org.bouncycastle.asn1.DefiniteLengthInputStream
-com.android.org.bouncycastle.asn1.InMemoryRepresentable
-com.android.org.bouncycastle.asn1.IndefiniteLengthInputStream
-com.android.org.bouncycastle.asn1.LimitedInputStream
-com.android.org.bouncycastle.asn1.StreamUtil
+com.android.org.bouncycastle.asn1.OIDTokenizer
com.android.org.bouncycastle.asn1.bc.BCObjectIdentifiers
com.android.org.bouncycastle.asn1.iana.IANAObjectIdentifiers
+com.android.org.bouncycastle.asn1.misc.MiscObjectIdentifiers
com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers
com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers
com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
-com.android.org.bouncycastle.asn1.x500.AttributeTypeAndValue
-com.android.org.bouncycastle.asn1.x500.RDN
-com.android.org.bouncycastle.asn1.x500.X500Name
-com.android.org.bouncycastle.asn1.x500.X500NameStyle
-com.android.org.bouncycastle.asn1.x500.style.AbstractX500NameStyle
-com.android.org.bouncycastle.asn1.x500.style.BCStyle
-com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier
-com.android.org.bouncycastle.asn1.x509.BasicConstraints
-com.android.org.bouncycastle.asn1.x509.Extension
-com.android.org.bouncycastle.asn1.x509.GeneralName
-com.android.org.bouncycastle.asn1.x509.GeneralNames
-com.android.org.bouncycastle.asn1.x509.PolicyInformation
-com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
-com.android.org.bouncycastle.asn1.x509.X509Extension
com.android.org.bouncycastle.asn1.x509.X509ObjectIdentifiers
com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers
-com.android.org.bouncycastle.crypto.Digest
-com.android.org.bouncycastle.crypto.ExtendedDigest
-com.android.org.bouncycastle.crypto.digests.AndroidDigestFactory
-com.android.org.bouncycastle.crypto.digests.AndroidDigestFactoryInterface
-com.android.org.bouncycastle.crypto.digests.AndroidDigestFactoryOpenSSL
-com.android.org.bouncycastle.crypto.digests.OpenSSLDigest
-com.android.org.bouncycastle.crypto.digests.OpenSSLDigest$SHA1
-com.android.org.bouncycastle.jcajce.PKIXExtendedParameters
-com.android.org.bouncycastle.jcajce.PKIXExtendedParameters$Builder
com.android.org.bouncycastle.jcajce.provider.asymmetric.DH$Mappings
com.android.org.bouncycastle.jcajce.provider.asymmetric.DSA$Mappings
com.android.org.bouncycastle.jcajce.provider.asymmetric.EC$Mappings
@@ -2575,40 +2788,27 @@
com.android.org.bouncycastle.jcajce.util.BCJcaJceHelper
com.android.org.bouncycastle.jcajce.util.JcaJceHelper
com.android.org.bouncycastle.jcajce.util.ProviderJcaJceHelper
-com.android.org.bouncycastle.jce.exception.ExtException
com.android.org.bouncycastle.jce.interfaces.BCKeyStore
-com.android.org.bouncycastle.jce.provider.AnnotatedException
com.android.org.bouncycastle.jce.provider.BouncyCastleProvider
com.android.org.bouncycastle.jce.provider.BouncyCastleProvider$1
com.android.org.bouncycastle.jce.provider.BouncyCastleProviderConfiguration
-com.android.org.bouncycastle.jce.provider.CertBlacklist
-com.android.org.bouncycastle.jce.provider.CertPathValidatorUtilities
-com.android.org.bouncycastle.jce.provider.PKIXCRLUtil
-com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi
-com.android.org.bouncycastle.jce.provider.PKIXNameConstraintValidator
-com.android.org.bouncycastle.jce.provider.PKIXNameConstraintValidatorException
-com.android.org.bouncycastle.jce.provider.PKIXPolicyNode
-com.android.org.bouncycastle.jce.provider.PrincipalUtils
-com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities
com.android.org.bouncycastle.util.Arrays
com.android.org.bouncycastle.util.Encodable
com.android.org.bouncycastle.util.Strings
-com.android.org.bouncycastle.util.encoders.Encoder
-com.android.org.bouncycastle.util.encoders.Hex
-com.android.org.bouncycastle.util.encoders.HexEncoder
-com.android.org.bouncycastle.util.io.Streams
-com.android.org.bouncycastle.x509.ExtendedPKIXParameters
+com.android.org.bouncycastle.util.Strings$1
com.android.org.conscrypt.AbstractSessionContext
com.android.org.conscrypt.AbstractSessionContext$1
com.android.org.conscrypt.AddressUtils
com.android.org.conscrypt.ByteArray
com.android.org.conscrypt.CertPinManager
+com.android.org.conscrypt.CertificatePriorityComparator
com.android.org.conscrypt.ChainStrengthAnalyzer
com.android.org.conscrypt.ClientSessionContext
com.android.org.conscrypt.ClientSessionContext$HostAndPort
com.android.org.conscrypt.CryptoUpcalls
com.android.org.conscrypt.FileClientSessionCache
com.android.org.conscrypt.FileClientSessionCache$Impl
+com.android.org.conscrypt.Hex
com.android.org.conscrypt.JSSEProvider
com.android.org.conscrypt.KeyManagerFactoryImpl
com.android.org.conscrypt.KeyManagerImpl
@@ -2624,14 +2824,17 @@
com.android.org.conscrypt.OpenSSLContextImpl
com.android.org.conscrypt.OpenSSLContextImpl$TLSv12
com.android.org.conscrypt.OpenSSLECGroupContext
+com.android.org.conscrypt.OpenSSLECKeyFactory
com.android.org.conscrypt.OpenSSLECPointContext
com.android.org.conscrypt.OpenSSLECPublicKey
+com.android.org.conscrypt.OpenSSLExtendedSessionImpl
com.android.org.conscrypt.OpenSSLKey
com.android.org.conscrypt.OpenSSLKeyHolder
com.android.org.conscrypt.OpenSSLMessageDigestJDK
com.android.org.conscrypt.OpenSSLMessageDigestJDK$MD5
com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA1
com.android.org.conscrypt.OpenSSLProvider
+com.android.org.conscrypt.OpenSSLRSAKeyFactory
com.android.org.conscrypt.OpenSSLRSAPublicKey
com.android.org.conscrypt.OpenSSLRandom
com.android.org.conscrypt.OpenSSLSessionImpl
@@ -2651,7 +2854,6 @@
com.android.org.conscrypt.PinEntryException
com.android.org.conscrypt.PinManagerException
com.android.org.conscrypt.Platform
-com.android.org.conscrypt.Platform$OpenSSLMapper
com.android.org.conscrypt.SSLClientSessionCache
com.android.org.conscrypt.SSLParametersImpl
com.android.org.conscrypt.SSLParametersImpl$AliasChooser
@@ -2660,12 +2862,10 @@
com.android.org.conscrypt.TrustManagerFactoryImpl
com.android.org.conscrypt.TrustManagerImpl
com.android.org.conscrypt.TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker
+com.android.org.conscrypt.TrustManagerImpl$TrustAnchorComparator
com.android.org.conscrypt.TrustedCertificateIndex
com.android.org.conscrypt.TrustedCertificateKeyStoreSpi
com.android.org.conscrypt.TrustedCertificateStore
-com.android.org.conscrypt.TrustedCertificateStore$1
-com.android.org.conscrypt.TrustedCertificateStore$2
-com.android.org.conscrypt.TrustedCertificateStore$CertSelector
com.android.org.conscrypt.util.ArrayUtils
com.android.server.NetworkManagementSocketTagger
com.android.server.NetworkManagementSocketTagger$1
@@ -2685,6 +2885,7 @@
dalvik.system.CloseGuard$Reporter
dalvik.system.DalvikLogHandler
dalvik.system.DalvikLogging
+dalvik.system.DexClassLoader
dalvik.system.DexFile
dalvik.system.DexFile$DFEnum
dalvik.system.DexPathList
@@ -2696,28 +2897,41 @@
dalvik.system.VMRuntime
dalvik.system.VMStack
dalvik.system.ZygoteHooks
+java.beans.ChangeListenerMap
java.beans.PropertyChangeEvent
+java.beans.PropertyChangeListener
java.beans.PropertyChangeSupport
+java.beans.PropertyChangeSupport$PropertyChangeListenerMap
+java.io.Bits
java.io.BufferedInputStream
java.io.BufferedOutputStream
java.io.BufferedReader
java.io.BufferedWriter
java.io.ByteArrayInputStream
java.io.ByteArrayOutputStream
+java.io.CharArrayWriter
java.io.Closeable
java.io.DataInput
java.io.DataInputStream
java.io.DataOutput
java.io.DataOutputStream
java.io.EOFException
+java.io.ExpiringCache
+java.io.ExpiringCache$1
+java.io.ExpiringCache$Entry
java.io.Externalizable
java.io.File
+java.io.File$PathStatus
+java.io.File$TempDirectory
java.io.FileDescriptor
-java.io.FileFilter
java.io.FileInputStream
+java.io.FileInputStream$UseManualSkipException
java.io.FileNotFoundException
java.io.FileOutputStream
java.io.FileReader
+java.io.FileSystem
+java.io.FileWriter
+java.io.FilenameFilter
java.io.FilterInputStream
java.io.FilterOutputStream
java.io.FilterReader
@@ -2727,13 +2941,17 @@
java.io.InputStreamReader
java.io.InterruptedIOException
java.io.InvalidObjectException
+java.io.NotSerializableException
java.io.ObjectInput
java.io.ObjectInputStream
+java.io.ObjectInputStream$BlockDataInputStream
+java.io.ObjectInputStream$HandleTable
+java.io.ObjectInputStream$HandleTable$HandleList
+java.io.ObjectInputStream$PeekInputStream
+java.io.ObjectInputStream$ValidationList
java.io.ObjectOutput
java.io.ObjectOutputStream
-java.io.ObjectOutputStream$PutField
java.io.ObjectStreamClass
-java.io.ObjectStreamClass$5
java.io.ObjectStreamConstants
java.io.ObjectStreamException
java.io.ObjectStreamField
@@ -2745,27 +2963,32 @@
java.io.PushbackReader
java.io.RandomAccessFile
java.io.Reader
+java.io.SequenceInputStream
java.io.Serializable
java.io.SerializablePermission
-java.io.SerializationHandleMap
+java.io.StreamCorruptedException
java.io.StringReader
java.io.StringWriter
java.io.UTFDataFormatException
+java.io.UnixFileSystem
java.io.UnsupportedEncodingException
java.io.Writer
java.lang.AbstractMethodError
java.lang.AbstractStringBuilder
java.lang.Appendable
java.lang.ArrayIndexOutOfBoundsException
+java.lang.ArrayStoreException
java.lang.AssertionError
java.lang.AutoCloseable
java.lang.Boolean
java.lang.BootClassLoader
java.lang.Byte
+java.lang.Byte$ByteCache
java.lang.CaseMapper
java.lang.CaseMapper$1
java.lang.CharSequence
java.lang.Character
+java.lang.Character$CharacterCache
java.lang.Character$Subset
java.lang.Character$UnicodeBlock
java.lang.Class
@@ -2787,24 +3010,30 @@
java.lang.Double
java.lang.Enum
java.lang.Enum$1
+java.lang.EnumConstantNotPresentException
java.lang.Error
java.lang.Exception
java.lang.Float
+java.lang.FloatingDecimal
+java.lang.FloatingDecimal$1
+java.lang.FloatingDecimal$2
java.lang.IllegalAccessException
java.lang.IllegalArgumentException
java.lang.IllegalStateException
java.lang.IllegalThreadStateException
java.lang.IncompatibleClassChangeError
java.lang.IndexOutOfBoundsException
+java.lang.InheritableThreadLocal
java.lang.InstantiationException
java.lang.Integer
-java.lang.IntegralToString
-java.lang.IntegralToString$1
+java.lang.Integer$IntegerCache
java.lang.InternalError
java.lang.InterruptedException
java.lang.Iterable
+java.lang.JavaLangAccess
java.lang.LinkageError
java.lang.Long
+java.lang.Long$LongCache
java.lang.Math
java.lang.Math$NoImagePreloadHolder
java.lang.NoClassDefFoundError
@@ -2818,16 +3047,19 @@
java.lang.Object
java.lang.OutOfMemoryError
java.lang.Package
+java.lang.Process
+java.lang.ProcessEnvironment
java.lang.Readable
-java.lang.RealToString
-java.lang.RealToString$1
java.lang.ReflectiveOperationException
java.lang.Runnable
java.lang.Runtime
java.lang.RuntimeException
java.lang.RuntimePermission
java.lang.SecurityException
+java.lang.SecurityManager
java.lang.Short
+java.lang.Short$ShortCache
+java.lang.Shutdown
java.lang.StackOverflowError
java.lang.StackTraceElement
java.lang.StrictMath
@@ -2835,28 +3067,40 @@
java.lang.String$CaseInsensitiveComparator
java.lang.StringBuffer
java.lang.StringBuilder
+java.lang.StringCoding
java.lang.StringFactory
java.lang.StringIndexOutOfBoundsException
-java.lang.StringToReal
-java.lang.StringToReal$StringExponentPair
java.lang.System
java.lang.System$PropertiesWithNonOverrideableDefaults
java.lang.Thread
+java.lang.Thread$1
+java.lang.Thread$Caches
java.lang.Thread$State
java.lang.Thread$UncaughtExceptionHandler
+java.lang.Thread$WeakClassKey
java.lang.ThreadDeath
java.lang.ThreadGroup
java.lang.ThreadLocal
-java.lang.ThreadLocal$Values
+java.lang.ThreadLocal$ThreadLocalMap
+java.lang.ThreadLocal$ThreadLocalMap$Entry
java.lang.Throwable
-java.lang.TwoEnumerationsInOne
+java.lang.Throwable$PrintStreamOrWriter
+java.lang.Throwable$SentinelHolder
+java.lang.Throwable$WrappedPrintStream
+java.lang.Throwable$WrappedPrintWriter
+java.lang.TypeNotPresentException
+java.lang.UNIXProcess
java.lang.UnsatisfiedLinkError
java.lang.UnsupportedOperationException
java.lang.VMClassLoader
java.lang.VirtualMachineError
java.lang.Void
java.lang.annotation.Annotation
+java.lang.annotation.AnnotationTypeMismatchException
+java.lang.annotation.IncompleteAnnotationException
java.lang.annotation.Inherited
+java.lang.annotation.Retention
+java.lang.annotation.Target
java.lang.ref.FinalizerReference
java.lang.ref.FinalizerReference$Sentinel
java.lang.ref.PhantomReference
@@ -2871,7 +3115,6 @@
java.lang.reflect.Array
java.lang.reflect.Constructor
java.lang.reflect.Field
-java.lang.reflect.Field$1
java.lang.reflect.GenericArrayType
java.lang.reflect.GenericDeclaration
java.lang.reflect.InvocationHandler
@@ -2889,52 +3132,67 @@
java.math.BigDecimal
java.math.BigInt
java.math.BigInteger
+java.math.BitLevel
+java.math.Multiplication
java.math.NativeBN
java.math.RoundingMode
+java.net.AbstractPlainDatagramSocketImpl
+java.net.AbstractPlainSocketImpl
java.net.AddressCache
java.net.AddressCache$AddressCacheEntry
java.net.AddressCache$AddressCacheKey
java.net.ConnectException
-java.net.ContentHandler
java.net.CookieHandler
+java.net.DatagramPacket
+java.net.DatagramSocketImpl
java.net.HttpURLConnection
+java.net.IDN
java.net.Inet4Address
java.net.Inet6Address
+java.net.Inet6AddressImpl
java.net.InetAddress
+java.net.InetAddress$1
+java.net.InetAddress$InetAddressHolder
+java.net.InetAddressImpl
java.net.InetSocketAddress
-java.net.InetUnixAddress
+java.net.InetSocketAddress$InetSocketAddressHolder
java.net.JarURLConnection
java.net.MalformedURLException
+java.net.NetworkInterface
+java.net.Parts
+java.net.PlainDatagramSocketImpl
java.net.PlainSocketImpl
java.net.ProtocolException
java.net.Proxy
java.net.Proxy$Type
java.net.ProxySelector
-java.net.ProxySelectorImpl
java.net.ResponseCache
java.net.ServerSocket
java.net.Socket
java.net.SocketAddress
java.net.SocketException
java.net.SocketImpl
+java.net.SocketInputStream
java.net.SocketOptions
+java.net.SocketOutputStream
java.net.SocketTimeoutException
+java.net.SocksConsts
+java.net.SocksSocketImpl
+java.net.SocksSocketImpl$3
java.net.URI
-java.net.URI$1
-java.net.URI$PartEncoder
+java.net.URI$Parser
java.net.URISyntaxException
java.net.URL
java.net.URLConnection
-java.net.URLConnection$DefaultContentHandler
+java.net.URLDecoder
java.net.URLEncoder
-java.net.URLEncoder$1
java.net.URLStreamHandler
java.net.URLStreamHandlerFactory
java.net.UnknownHostException
+java.nio.Bits
java.nio.Buffer
java.nio.BufferOverflowException
java.nio.BufferUnderflowException
-java.nio.ByteArrayBuffer
java.nio.ByteBuffer
java.nio.ByteBufferAsCharBuffer
java.nio.ByteBufferAsDoubleBuffer
@@ -2943,42 +3201,43 @@
java.nio.ByteBufferAsLongBuffer
java.nio.ByteBufferAsShortBuffer
java.nio.ByteOrder
-java.nio.CharArrayBuffer
java.nio.CharBuffer
-java.nio.CharSequenceAdapter
java.nio.DirectByteBuffer
+java.nio.DirectByteBuffer$MemoryRef
java.nio.DoubleBuffer
-java.nio.FileChannelImpl
-java.nio.FileChannelImpl$1
-java.nio.FileChannelImpl$FileLockImpl
java.nio.FloatBuffer
+java.nio.HeapByteBuffer
+java.nio.HeapCharBuffer
java.nio.IntBuffer
java.nio.InvalidMarkException
java.nio.LongBuffer
java.nio.MappedByteBuffer
-java.nio.MemoryBlock
-java.nio.MemoryBlock$MemoryMappedBlock
-java.nio.MemoryBlock$NonMovableHeapBlock
-java.nio.MemoryBlock$UnmanagedBlock
java.nio.NIOAccess
-java.nio.NioUtils
java.nio.ReadOnlyBufferException
java.nio.ShortBuffer
+java.nio.StringCharBuffer
java.nio.channels.AsynchronousCloseException
java.nio.channels.ByteChannel
java.nio.channels.Channel
java.nio.channels.ClosedByInterruptException
java.nio.channels.ClosedChannelException
+java.nio.channels.DatagramChannel
java.nio.channels.FileChannel
java.nio.channels.FileChannel$MapMode
java.nio.channels.FileLock
java.nio.channels.GatheringByteChannel
java.nio.channels.InterruptibleChannel
+java.nio.channels.NetworkChannel
java.nio.channels.ReadableByteChannel
java.nio.channels.ScatteringByteChannel
+java.nio.channels.SeekableByteChannel
+java.nio.channels.SelectableChannel
+java.nio.channels.ServerSocketChannel
+java.nio.channels.SocketChannel
java.nio.channels.WritableByteChannel
java.nio.channels.spi.AbstractInterruptibleChannel
java.nio.channels.spi.AbstractInterruptibleChannel$1
+java.nio.channels.spi.AbstractSelectableChannel
java.nio.charset.CharacterCodingException
java.nio.charset.Charset
java.nio.charset.CharsetDecoder
@@ -2987,45 +3246,62 @@
java.nio.charset.CharsetEncoderICU
java.nio.charset.CharsetICU
java.nio.charset.CoderResult
+java.nio.charset.CoderResult$1
+java.nio.charset.CoderResult$2
+java.nio.charset.CoderResult$Cache
java.nio.charset.CodingErrorAction
java.nio.charset.IllegalCharsetNameException
-java.nio.charset.ModifiedUtf8
java.nio.charset.StandardCharsets
java.nio.charset.UnsupportedCharsetException
+java.security.AccessControlContext
java.security.AccessControlException
java.security.AccessController
+java.security.AlgorithmConstraints
+java.security.AlgorithmParameters
+java.security.AlgorithmParametersSpi
java.security.BasicPermission
-java.security.DigestException
+java.security.BasicPermissionCollection
+java.security.CryptoPrimitive
java.security.GeneralSecurityException
java.security.Guard
java.security.InvalidAlgorithmParameterException
java.security.InvalidKeyException
+java.security.InvalidParameterException
java.security.Key
java.security.KeyException
+java.security.KeyFactory
java.security.KeyFactorySpi
java.security.KeyManagementException
+java.security.KeyPair
java.security.KeyStore
+java.security.KeyStore$1
+java.security.KeyStore$LoadStoreParameter
java.security.KeyStoreException
java.security.KeyStoreSpi
java.security.MessageDigest
-java.security.MessageDigest$MessageDigestImpl
+java.security.MessageDigest$Delegate
java.security.MessageDigestSpi
java.security.NoSuchAlgorithmException
java.security.NoSuchProviderException
java.security.Permission
+java.security.PermissionCollection
java.security.Principal
java.security.PrivateKey
java.security.PrivilegedAction
+java.security.PrivilegedActionException
+java.security.PrivilegedExceptionAction
java.security.ProtectionDomain
java.security.Provider
+java.security.Provider$EngineDescription
java.security.Provider$Service
+java.security.Provider$ServiceKey
+java.security.Provider$UString
java.security.PublicKey
java.security.SecureRandom
java.security.SecureRandomSpi
java.security.Security
-java.security.Security$SecurityDoor
java.security.Signature
-java.security.Signature$SignatureImpl
+java.security.Signature$Delegate
java.security.SignatureException
java.security.SignatureSpi
java.security.UnrecoverableEntryException
@@ -3033,15 +3309,14 @@
java.security.cert.CRL
java.security.cert.CRLException
java.security.cert.CertPath
-java.security.cert.CertPathBuilderException
+java.security.cert.CertPathChecker
+java.security.cert.CertPathHelperImpl
java.security.cert.CertPathParameters
java.security.cert.CertPathValidator
java.security.cert.CertPathValidatorException
java.security.cert.CertPathValidatorResult
java.security.cert.CertPathValidatorSpi
java.security.cert.CertSelector
-java.security.cert.CertStoreException
-java.security.cert.CertStoreParameters
java.security.cert.Certificate
java.security.cert.CertificateEncodingException
java.security.cert.CertificateException
@@ -3050,11 +3325,14 @@
java.security.cert.CertificateFactorySpi
java.security.cert.CertificateNotYetValidException
java.security.cert.CertificateParsingException
+java.security.cert.Extension
java.security.cert.PKIXCertPathChecker
java.security.cert.PKIXCertPathValidatorResult
java.security.cert.PKIXParameters
+java.security.cert.PKIXRevocationChecker
java.security.cert.PolicyNode
java.security.cert.TrustAnchor
+java.security.cert.X509CRL
java.security.cert.X509CertSelector
java.security.cert.X509Certificate
java.security.cert.X509Extension
@@ -3064,51 +3342,70 @@
java.security.interfaces.ECPrivateKey
java.security.interfaces.ECPublicKey
java.security.interfaces.RSAKey
+java.security.interfaces.RSAPrivateCrtKey
java.security.interfaces.RSAPrivateKey
java.security.interfaces.RSAPublicKey
java.security.spec.AlgorithmParameterSpec
java.security.spec.ECField
+java.security.spec.ECFieldF2m
java.security.spec.ECFieldFp
java.security.spec.ECParameterSpec
java.security.spec.ECPoint
+java.security.spec.ECPrivateKeySpec
+java.security.spec.ECPublicKeySpec
java.security.spec.EllipticCurve
+java.security.spec.EncodedKeySpec
java.security.spec.InvalidKeySpecException
java.security.spec.InvalidParameterSpecException
java.security.spec.KeySpec
+java.security.spec.PKCS8EncodedKeySpec
+java.security.spec.RSAPrivateCrtKeySpec
+java.security.spec.RSAPrivateKeySpec
+java.security.spec.RSAPublicKeySpec
+java.security.spec.X509EncodedKeySpec
+java.sql.Timestamp
java.text.AttributedCharacterIterator$Attribute
-java.text.Bidi
-java.text.Bidi$Run
+java.text.CalendarBuilder
java.text.Collator
java.text.DateFormat
java.text.DateFormat$Field
java.text.DateFormatSymbols
java.text.DecimalFormat
java.text.DecimalFormatSymbols
+java.text.DontCareFieldPosition
+java.text.DontCareFieldPosition$1
java.text.FieldPosition
java.text.Format
java.text.Format$Field
+java.text.Format$FieldDelegate
+java.text.Normalizer
+java.text.Normalizer$Form
java.text.NumberFormat
-java.text.NumberFormat$Field
java.text.ParseException
java.text.ParsePosition
java.text.RuleBasedCollator
java.text.SimpleDateFormat
+java.text.spi.DateFormatProvider
+java.text.spi.DateFormatSymbolsProvider
+java.text.spi.DecimalFormatSymbolsProvider
+java.text.spi.NumberFormatProvider
java.util.AbstractCollection
java.util.AbstractList
-java.util.AbstractList$FullListIterator
-java.util.AbstractList$SimpleListIterator
-java.util.AbstractList$SubAbstractList
-java.util.AbstractList$SubAbstractListRandomAccess
+java.util.AbstractList$Itr
+java.util.AbstractList$ListItr
java.util.AbstractMap
java.util.AbstractMap$1
java.util.AbstractMap$2
-java.util.AbstractMap$2$1
+java.util.AbstractMap$SimpleImmutableEntry
java.util.AbstractQueue
java.util.AbstractSequentialList
java.util.AbstractSet
java.util.ArrayDeque
java.util.ArrayList
-java.util.ArrayList$ArrayListIterator
+java.util.ArrayList$Itr
+java.util.ArrayList$ListItr
+java.util.ArrayList$SubList
+java.util.ArrayList$SubList$1
java.util.Arrays
java.util.Arrays$ArrayList
java.util.BitSet
@@ -3117,7 +3414,6 @@
java.util.Collections
java.util.Collections$1
java.util.Collections$2
-java.util.Collections$3
java.util.Collections$AsLIFOQueue
java.util.Collections$CheckedCollection
java.util.Collections$CheckedList
@@ -3127,7 +3423,10 @@
java.util.Collections$CheckedSortedMap
java.util.Collections$CheckedSortedSet
java.util.Collections$CopiesList
+java.util.Collections$EmptyEnumeration
+java.util.Collections$EmptyIterator
java.util.Collections$EmptyList
+java.util.Collections$EmptyListIterator
java.util.Collections$EmptyMap
java.util.Collections$EmptySet
java.util.Collections$ReverseComparator
@@ -3136,7 +3435,6 @@
java.util.Collections$SingletonList
java.util.Collections$SingletonMap
java.util.Collections$SingletonSet
-java.util.Collections$SingletonSet$1
java.util.Collections$SynchronizedCollection
java.util.Collections$SynchronizedList
java.util.Collections$SynchronizedMap
@@ -3147,10 +3445,11 @@
java.util.Collections$UnmodifiableCollection
java.util.Collections$UnmodifiableCollection$1
java.util.Collections$UnmodifiableList
+java.util.Collections$UnmodifiableList$1
java.util.Collections$UnmodifiableMap
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet
java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1
-java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableMapEntry
+java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry
java.util.Collections$UnmodifiableRandomAccessList
java.util.Collections$UnmodifiableSet
java.util.Collections$UnmodifiableSortedMap
@@ -3164,110 +3463,139 @@
java.util.Dictionary
java.util.DualPivotQuicksort
java.util.EnumMap
+java.util.EnumMap$1
+java.util.EnumMap$EnumMapIterator
java.util.EnumSet
java.util.Enumeration
java.util.EventListener
java.util.EventObject
java.util.Formattable
java.util.Formatter
-java.util.Formatter$1
-java.util.Formatter$CachedDecimalFormat
+java.util.Formatter$Conversion
+java.util.Formatter$FixedString
+java.util.Formatter$Flags
+java.util.Formatter$FormatSpecifier
java.util.Formatter$FormatSpecifierParser
-java.util.Formatter$FormatToken
+java.util.Formatter$FormatString
java.util.GregorianCalendar
java.util.HashMap
java.util.HashMap$EntryIterator
java.util.HashMap$EntrySet
java.util.HashMap$HashIterator
java.util.HashMap$HashMapEntry
+java.util.HashMap$Holder
java.util.HashMap$KeyIterator
java.util.HashMap$KeySet
java.util.HashMap$ValueIterator
java.util.HashMap$Values
java.util.HashSet
java.util.Hashtable
-java.util.Hashtable$HashIterator
+java.util.Hashtable$EntrySet
+java.util.Hashtable$Enumerator
java.util.Hashtable$HashtableEntry
-java.util.Hashtable$KeyEnumeration
-java.util.Hashtable$ValueIterator
-java.util.Hashtable$Values
+java.util.Hashtable$Holder
+java.util.Hashtable$KeySet
+java.util.Hashtable$ValueCollection
java.util.IdentityHashMap
+java.util.IdentityHashMap$EntryIterator
+java.util.IdentityHashMap$EntrySet
java.util.IdentityHashMap$IdentityHashMapIterator
+java.util.IdentityHashMap$KeySet
java.util.IllegalFormatException
java.util.IllformedLocaleException
java.util.Iterator
java.util.LinkedHashMap
java.util.LinkedHashMap$EntryIterator
java.util.LinkedHashMap$KeyIterator
-java.util.LinkedHashMap$LinkedEntry
java.util.LinkedHashMap$LinkedHashIterator
+java.util.LinkedHashMap$LinkedHashMapEntry
java.util.LinkedHashMap$ValueIterator
java.util.LinkedHashSet
java.util.LinkedList
-java.util.LinkedList$Link
-java.util.LinkedList$LinkIterator
+java.util.LinkedList$ListItr
+java.util.LinkedList$Node
java.util.List
java.util.ListIterator
java.util.Locale
java.util.Locale$Builder
-java.util.Locale$NoImagePreloadHolder
+java.util.Locale$Cache
+java.util.Locale$Category
+java.util.Locale$LocaleKey
java.util.Map
java.util.Map$Entry
-java.util.MapEntry
-java.util.MapEntry$Type
-java.util.MiniEnumSet
-java.util.MiniEnumSet$MiniEnumSetIterator
java.util.MissingResourceException
java.util.NavigableMap
java.util.NavigableSet
java.util.NoSuchElementException
java.util.Objects
java.util.PriorityQueue
+java.util.PriorityQueue$Itr
java.util.Properties
+java.util.Properties$LineReader
+java.util.PropertyResourceBundle
java.util.Queue
java.util.Random
java.util.RandomAccess
+java.util.RandomAccessSubList
+java.util.RegularEnumSet
+java.util.RegularEnumSet$EnumSetIterator
java.util.ResourceBundle
-java.util.ResourceBundle$MissingBundle
+java.util.ResourceBundle$1
+java.util.ResourceBundle$BundleReference
+java.util.ResourceBundle$CacheKey
+java.util.ResourceBundle$CacheKeyReference
+java.util.ResourceBundle$Control
+java.util.ResourceBundle$Control$1
+java.util.ResourceBundle$Control$CandidateListCache
+java.util.ResourceBundle$LoaderReference
+java.util.ResourceBundle$RBClassLoader
+java.util.ResourceBundle$RBClassLoader$1
+java.util.Scanner
+java.util.ServiceLoader
+java.util.ServiceLoader$1
+java.util.ServiceLoader$LazyIterator
java.util.Set
java.util.SimpleTimeZone
java.util.SortedMap
java.util.SortedSet
java.util.Stack
java.util.StringTokenizer
+java.util.SubList
+java.util.TaskQueue
java.util.TimSort
java.util.TimeZone
java.util.Timer
-java.util.Timer$FinalizerHelper
-java.util.Timer$TimerImpl
-java.util.Timer$TimerImpl$TimerHeap
+java.util.Timer$1
java.util.TimerTask
+java.util.TimerThread
java.util.TreeMap
-java.util.TreeMap$1
-java.util.TreeMap$Bound
-java.util.TreeMap$Bound$1
-java.util.TreeMap$Bound$2
-java.util.TreeMap$Bound$3
-java.util.TreeMap$BoundedMap
-java.util.TreeMap$BoundedMap$BoundedIterator
+java.util.TreeMap$AscendingSubMap
+java.util.TreeMap$EntryIterator
java.util.TreeMap$EntrySet
-java.util.TreeMap$EntrySet$1
+java.util.TreeMap$KeyIterator
java.util.TreeMap$KeySet
-java.util.TreeMap$KeySet$1
-java.util.TreeMap$MapIterator
-java.util.TreeMap$Node
-java.util.TreeMap$Relation
+java.util.TreeMap$NavigableSubMap
+java.util.TreeMap$PrivateEntryIterator
+java.util.TreeMap$TreeMapEntry
+java.util.TreeMap$ValueIterator
+java.util.TreeMap$Values
java.util.TreeSet
java.util.UUID
+java.util.UUID$Holder
java.util.Vector
java.util.Vector$1
+java.util.Vector$Itr
java.util.WeakHashMap
-java.util.WeakHashMap$2
-java.util.WeakHashMap$2$1
java.util.WeakHashMap$Entry
-java.util.WeakHashMap$Entry$Type
+java.util.WeakHashMap$EntrySet
java.util.WeakHashMap$HashIterator
+java.util.WeakHashMap$Holder
+java.util.WeakHashMap$KeyIterator
+java.util.WeakHashMap$KeySet
+java.util.WeakHashMap$Values
+java.util.XMLUtils
java.util.concurrent.AbstractExecutorService
+java.util.concurrent.ArrayBlockingQueue
java.util.concurrent.BlockingQueue
java.util.concurrent.Callable
java.util.concurrent.CancellationException
@@ -3283,6 +3611,8 @@
java.util.concurrent.ConcurrentHashMap$Traverser
java.util.concurrent.ConcurrentHashMap$TreeBin
java.util.concurrent.ConcurrentHashMap$TreeNode
+java.util.concurrent.ConcurrentHashMap$ValueIterator
+java.util.concurrent.ConcurrentHashMap$ValuesView
java.util.concurrent.ConcurrentLinkedQueue
java.util.concurrent.ConcurrentLinkedQueue$Node
java.util.concurrent.ConcurrentMap
@@ -3340,6 +3670,8 @@
java.util.concurrent.atomic.AtomicInteger
java.util.concurrent.atomic.AtomicLong
java.util.concurrent.atomic.AtomicReference
+java.util.concurrent.atomic.AtomicReferenceFieldUpdater
+java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl
java.util.concurrent.locks.AbstractOwnableSynchronizer
java.util.concurrent.locks.AbstractQueuedSynchronizer
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject
@@ -3357,31 +3689,38 @@
java.util.concurrent.locks.ReentrantReadWriteLock$Sync
java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter
java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock
-java.util.jar.Attributes
-java.util.jar.Attributes$Name
java.util.jar.JarEntry
java.util.jar.JarFile
-java.util.jar.JarFile$JarFileEnumerator
-java.util.logging.ConsoleHandler
+java.util.jar.JarFile$1
+java.util.jar.JarFile$JarFileEntry
java.util.logging.ErrorManager
-java.util.logging.Filter
java.util.logging.Formatter
java.util.logging.Handler
java.util.logging.Level
+java.util.logging.Level$KnownLevel
java.util.logging.LogManager
java.util.logging.LogManager$1
+java.util.logging.LogManager$2
+java.util.logging.LogManager$4
+java.util.logging.LogManager$Cleaner
+java.util.logging.LogManager$LogNode
+java.util.logging.LogManager$LoggerContext
+java.util.logging.LogManager$LoggerContext$1
+java.util.logging.LogManager$LoggerWeakRef
+java.util.logging.LogManager$RootLogger
+java.util.logging.LogManager$SystemLoggerContext
+java.util.logging.LogRecord
java.util.logging.Logger
-java.util.logging.Logger$1
java.util.logging.LoggingPermission
-java.util.logging.SimpleFormatter
-java.util.logging.StreamHandler
+java.util.logging.LoggingProxyImpl
java.util.regex.MatchResult
java.util.regex.Matcher
java.util.regex.Pattern
java.util.regex.PatternSyntaxException
-java.util.regex.Splitter
+java.util.spi.LocaleServiceProvider
java.util.zip.Adler32
java.util.zip.CRC32
+java.util.zip.CheckedInputStream
java.util.zip.Checksum
java.util.zip.DataFormatException
java.util.zip.Deflater
@@ -3390,26 +3729,38 @@
java.util.zip.GZIPOutputStream
java.util.zip.Inflater
java.util.zip.InflaterInputStream
-java.util.zip.Zip64
+java.util.zip.ZStreamRef
+java.util.zip.ZipCoder
java.util.zip.ZipConstants
java.util.zip.ZipEntry
java.util.zip.ZipFile
java.util.zip.ZipFile$1
-java.util.zip.ZipFile$EocdRecord
-java.util.zip.ZipFile$RAFStream
-java.util.zip.ZipFile$ZipInflaterInputStream
+java.util.zip.ZipFile$ZipFileInflaterInputStream
+java.util.zip.ZipFile$ZipFileInputStream
javax.crypto.BadPaddingException
javax.crypto.Cipher
+javax.crypto.Cipher$CipherSpiAndProvider
+javax.crypto.Cipher$InitParams
+javax.crypto.Cipher$InitType
javax.crypto.Cipher$NeedToSet
+javax.crypto.Cipher$SpiAndProviderUpdater
+javax.crypto.Cipher$Transform
javax.crypto.CipherSpi
javax.crypto.IllegalBlockSizeException
+javax.crypto.JceSecurity
+javax.crypto.Mac
javax.crypto.NoSuchPaddingException
+javax.crypto.NullCipher
javax.crypto.SecretKey
javax.crypto.ShortBufferException
javax.crypto.spec.IvParameterSpec
javax.crypto.spec.SecretKeySpec
javax.microedition.khronos.egl.EGL
javax.microedition.khronos.egl.EGL10
+javax.microedition.khronos.egl.EGLConfig
+javax.microedition.khronos.egl.EGLContext
+javax.microedition.khronos.egl.EGLDisplay
+javax.microedition.khronos.egl.EGLSurface
javax.microedition.khronos.opengles.GL
javax.microedition.khronos.opengles.GL10
javax.microedition.khronos.opengles.GL10Ext
@@ -3419,56 +3770,61 @@
javax.net.DefaultSocketFactory
javax.net.ServerSocketFactory
javax.net.SocketFactory
-javax.net.ssl.DistinguishedNameParser
+javax.net.ssl.ExtendedSSLSession
+javax.net.ssl.HandshakeCompletedEvent
javax.net.ssl.HandshakeCompletedListener
javax.net.ssl.HostnameVerifier
javax.net.ssl.HttpsURLConnection
javax.net.ssl.KeyManager
javax.net.ssl.KeyManagerFactory
+javax.net.ssl.KeyManagerFactory$1
javax.net.ssl.KeyManagerFactorySpi
javax.net.ssl.SSLContext
javax.net.ssl.SSLContextSpi
javax.net.ssl.SSLEngine
javax.net.ssl.SSLException
+javax.net.ssl.SSLHandshakeException
+javax.net.ssl.SSLParameters
javax.net.ssl.SSLPeerUnverifiedException
javax.net.ssl.SSLProtocolException
+javax.net.ssl.SSLServerSocket
javax.net.ssl.SSLServerSocketFactory
javax.net.ssl.SSLSession
+javax.net.ssl.SSLSessionBindingEvent
+javax.net.ssl.SSLSessionBindingListener
javax.net.ssl.SSLSessionContext
javax.net.ssl.SSLSocket
javax.net.ssl.SSLSocketFactory
+javax.net.ssl.SSLSocketFactory$1
javax.net.ssl.TrustManager
javax.net.ssl.TrustManagerFactory
+javax.net.ssl.TrustManagerFactory$1
javax.net.ssl.TrustManagerFactorySpi
javax.net.ssl.X509ExtendedKeyManager
+javax.net.ssl.X509ExtendedTrustManager
javax.net.ssl.X509KeyManager
javax.net.ssl.X509TrustManager
+javax.security.auth.callback.UnsupportedCallbackException
javax.security.auth.x500.X500Principal
javax.security.cert.Certificate
javax.security.cert.CertificateException
javax.security.cert.X509Certificate
javax.xml.parsers.ParserConfigurationException
-libcore.icu.AlphabeticIndex
-libcore.icu.AlphabeticIndex$ImmutableIndex
+javax.xml.transform.TransformerConfigurationException
+javax.xml.transform.TransformerException
libcore.icu.DateIntervalFormat
-libcore.icu.DateIntervalFormat$FormatterCache
libcore.icu.DateUtilsBridge
libcore.icu.ICU
libcore.icu.LocaleData
-libcore.icu.NativeCollation
libcore.icu.NativeConverter
-libcore.icu.NativeDecimalFormat
-libcore.icu.NativeDecimalFormat$FieldPositionIterator
-libcore.icu.NativeIDN
-libcore.icu.NativeNormalizer
-libcore.icu.NativePluralRules
-libcore.icu.RuleBasedCollatorICU
libcore.icu.TimeZoneNames
-libcore.icu.Transliterator
libcore.internal.StringPool
libcore.io.AsynchronousCloseMonitor
libcore.io.BlockGuardOs
libcore.io.BufferIterator
+libcore.io.ClassPathURLStreamHandler
+libcore.io.ClassPathURLStreamHandler$ClassPathURLConnection
+libcore.io.ClassPathURLStreamHandler$ClassPathURLConnection$1
libcore.io.DropBox
libcore.io.DropBox$DefaultReporter
libcore.io.DropBox$Reporter
@@ -3476,7 +3832,6 @@
libcore.io.EventLogger$DefaultReporter
libcore.io.EventLogger$Reporter
libcore.io.ForwardingOs
-libcore.io.HeapBufferIterator
libcore.io.IoBridge
libcore.io.IoUtils
libcore.io.IoUtils$FileReader
@@ -3486,19 +3841,13 @@
libcore.io.NioBufferIterator
libcore.io.Os
libcore.io.Posix
-libcore.io.Streams
libcore.math.MathUtils
libcore.net.NetworkSecurityPolicy
+libcore.net.NetworkSecurityPolicy$DefaultNetworkSecurityPolicy
libcore.net.UriCodec
libcore.net.event.NetworkEventDispatcher
libcore.net.event.NetworkEventListener
-libcore.net.url.FileHandler
-libcore.net.url.FileURLConnection
-libcore.net.url.FileURLConnection$1
-libcore.net.url.JarHandler
-libcore.net.url.JarURLConnectionImpl
-libcore.net.url.JarURLConnectionImpl$JarURLConnectionInputStream
-libcore.net.url.UrlUtils
+libcore.reflect.AnnotatedElements
libcore.reflect.AnnotationAccess
libcore.reflect.AnnotationFactory
libcore.reflect.AnnotationMember
@@ -3508,13 +3857,15 @@
libcore.reflect.ListOfTypes
libcore.reflect.ListOfVariables
libcore.reflect.ParameterizedTypeImpl
+libcore.reflect.TypeVariableImpl
libcore.reflect.Types
libcore.util.BasicLruCache
libcore.util.CharsetUtils
libcore.util.CollectionUtils
-libcore.util.CollectionUtils$1
-libcore.util.CollectionUtils$1$1
libcore.util.EmptyArray
+libcore.util.NativeAllocationRegistry
+libcore.util.NativeAllocationRegistry$CleanerRunner
+libcore.util.NativeAllocationRegistry$CleanerThunk
libcore.util.Objects
libcore.util.ZoneInfo
libcore.util.ZoneInfo$CheckedArithmeticException
@@ -3522,280 +3873,66 @@
libcore.util.ZoneInfoDB
libcore.util.ZoneInfoDB$TzData
libcore.util.ZoneInfoDB$TzData$1
-org.apache.commons.logging.Log
-org.apache.commons.logging.LogFactory
-org.apache.commons.logging.impl.Jdk14Logger
-org.apache.commons.logging.impl.WeakHashtable
org.apache.harmony.dalvik.NativeTestTarget
org.apache.harmony.dalvik.ddmc.Chunk
org.apache.harmony.dalvik.ddmc.ChunkHandler
org.apache.harmony.dalvik.ddmc.DdmServer
org.apache.harmony.dalvik.ddmc.DdmVmInternal
org.apache.harmony.luni.internal.util.TimezoneGetter
-org.apache.harmony.security.asn1.ASN1Any
-org.apache.harmony.security.asn1.ASN1Choice
-org.apache.harmony.security.asn1.ASN1Constants
-org.apache.harmony.security.asn1.ASN1Constructed
-org.apache.harmony.security.asn1.ASN1Oid
-org.apache.harmony.security.asn1.ASN1Oid$1
-org.apache.harmony.security.asn1.ASN1Primitive
-org.apache.harmony.security.asn1.ASN1Sequence
-org.apache.harmony.security.asn1.ASN1SequenceOf
-org.apache.harmony.security.asn1.ASN1SetOf
-org.apache.harmony.security.asn1.ASN1StringType
-org.apache.harmony.security.asn1.ASN1StringType$1
-org.apache.harmony.security.asn1.ASN1StringType$2
-org.apache.harmony.security.asn1.ASN1StringType$3
-org.apache.harmony.security.asn1.ASN1StringType$4
-org.apache.harmony.security.asn1.ASN1StringType$5
-org.apache.harmony.security.asn1.ASN1StringType$6
-org.apache.harmony.security.asn1.ASN1StringType$7
-org.apache.harmony.security.asn1.ASN1StringType$ASN1StringUTF8Type
-org.apache.harmony.security.asn1.ASN1Type
-org.apache.harmony.security.asn1.ASN1TypeCollection
-org.apache.harmony.security.asn1.ASN1ValueCollection
-org.apache.harmony.security.asn1.BerInputStream
-org.apache.harmony.security.asn1.BerOutputStream
-org.apache.harmony.security.asn1.DerInputStream
-org.apache.harmony.security.asn1.DerOutputStream
-org.apache.harmony.security.provider.crypto.CryptoProvider
-org.apache.harmony.security.utils.AlgNameMapper
-org.apache.harmony.security.utils.AlgNameMapperSource
-org.apache.harmony.security.utils.ObjectIdentifier
-org.apache.harmony.security.x501.AttributeTypeAndValue
-org.apache.harmony.security.x501.AttributeTypeAndValue$1
-org.apache.harmony.security.x501.AttributeTypeAndValue$2
-org.apache.harmony.security.x501.AttributeTypeAndValueComparator
-org.apache.harmony.security.x501.AttributeValue
-org.apache.harmony.security.x501.DirectoryString
-org.apache.harmony.security.x501.DirectoryString$1
-org.apache.harmony.security.x501.Name
-org.apache.harmony.security.x501.Name$1
org.apache.harmony.xml.ExpatAttributes
org.apache.harmony.xml.ExpatParser
-org.apache.http.ConnectionReuseStrategy
-org.apache.http.FormattedHeader
org.apache.http.Header
-org.apache.http.HeaderElement
-org.apache.http.HeaderElementIterator
org.apache.http.HeaderIterator
-org.apache.http.HttpClientConnection
-org.apache.http.HttpConnection
-org.apache.http.HttpConnectionMetrics
org.apache.http.HttpEntity
org.apache.http.HttpEntityEnclosingRequest
org.apache.http.HttpException
org.apache.http.HttpHost
-org.apache.http.HttpInetConnection
org.apache.http.HttpMessage
org.apache.http.HttpRequest
-org.apache.http.HttpRequestInterceptor
org.apache.http.HttpResponse
-org.apache.http.HttpResponseFactory
-org.apache.http.HttpResponseInterceptor
org.apache.http.HttpVersion
org.apache.http.NameValuePair
-org.apache.http.ParseException
org.apache.http.ProtocolException
org.apache.http.ProtocolVersion
org.apache.http.ReasonPhraseCatalog
-org.apache.http.RequestLine
org.apache.http.StatusLine
-org.apache.http.auth.AuthSchemeFactory
-org.apache.http.auth.AuthSchemeRegistry
-org.apache.http.auth.AuthState
-org.apache.http.auth.AuthenticationException
-org.apache.http.client.AuthenticationHandler
-org.apache.http.client.CookieStore
-org.apache.http.client.CredentialsProvider
+org.apache.http.client.ClientProtocolException
org.apache.http.client.HttpClient
-org.apache.http.client.HttpRequestRetryHandler
-org.apache.http.client.RedirectHandler
-org.apache.http.client.RequestDirector
org.apache.http.client.ResponseHandler
-org.apache.http.client.UserTokenHandler
org.apache.http.client.methods.AbortableHttpRequest
org.apache.http.client.methods.HttpEntityEnclosingRequestBase
org.apache.http.client.methods.HttpGet
org.apache.http.client.methods.HttpPost
org.apache.http.client.methods.HttpRequestBase
org.apache.http.client.methods.HttpUriRequest
-org.apache.http.client.params.HttpClientParams
-org.apache.http.client.protocol.RequestAddCookies
-org.apache.http.client.protocol.RequestDefaultHeaders
-org.apache.http.client.protocol.RequestProxyAuthentication
-org.apache.http.client.protocol.RequestTargetAuthentication
-org.apache.http.client.protocol.ResponseProcessCookies
-org.apache.http.client.utils.URIUtils
-org.apache.http.conn.BasicManagedEntity
+org.apache.http.client.utils.URLEncodedUtils
org.apache.http.conn.ClientConnectionManager
-org.apache.http.conn.ClientConnectionOperator
-org.apache.http.conn.ClientConnectionRequest
org.apache.http.conn.ConnectTimeoutException
-org.apache.http.conn.ConnectionKeepAliveStrategy
-org.apache.http.conn.ConnectionReleaseTrigger
-org.apache.http.conn.EofSensorInputStream
-org.apache.http.conn.EofSensorWatcher
-org.apache.http.conn.ManagedClientConnection
-org.apache.http.conn.OperatedClientConnection
org.apache.http.conn.params.ConnManagerPNames
org.apache.http.conn.params.ConnManagerParams
org.apache.http.conn.params.ConnManagerParams$1
org.apache.http.conn.params.ConnPerRoute
-org.apache.http.conn.params.ConnPerRouteBean
-org.apache.http.conn.params.ConnRoutePNames
-org.apache.http.conn.params.ConnRouteParams
-org.apache.http.conn.routing.BasicRouteDirector
-org.apache.http.conn.routing.HttpRoute
-org.apache.http.conn.routing.HttpRouteDirector
-org.apache.http.conn.routing.HttpRoutePlanner
-org.apache.http.conn.routing.RouteInfo
-org.apache.http.conn.routing.RouteInfo$LayerType
-org.apache.http.conn.routing.RouteInfo$TunnelType
-org.apache.http.conn.routing.RouteTracker
org.apache.http.conn.scheme.LayeredSocketFactory
-org.apache.http.conn.scheme.PlainSocketFactory
-org.apache.http.conn.scheme.Scheme
-org.apache.http.conn.scheme.SchemeRegistry
org.apache.http.conn.scheme.SocketFactory
-org.apache.http.conn.ssl.AbstractVerifier
-org.apache.http.conn.ssl.AllowAllHostnameVerifier
-org.apache.http.conn.ssl.BrowserCompatHostnameVerifier
-org.apache.http.conn.ssl.SSLSocketFactory
-org.apache.http.conn.ssl.StrictHostnameVerifier
-org.apache.http.conn.ssl.X509HostnameVerifier
-org.apache.http.cookie.CookieSpecFactory
-org.apache.http.cookie.CookieSpecRegistry
-org.apache.http.cookie.MalformedCookieException
org.apache.http.entity.AbstractHttpEntity
org.apache.http.entity.BasicHttpEntity
org.apache.http.entity.ByteArrayEntity
-org.apache.http.entity.ContentLengthStrategy
-org.apache.http.entity.HttpEntityWrapper
-org.apache.http.impl.AbstractHttpClientConnection
-org.apache.http.impl.DefaultConnectionReuseStrategy
-org.apache.http.impl.DefaultHttpResponseFactory
-org.apache.http.impl.EnglishReasonPhraseCatalog
-org.apache.http.impl.HttpConnectionMetricsImpl
-org.apache.http.impl.SocketHttpClientConnection
-org.apache.http.impl.auth.BasicSchemeFactory
-org.apache.http.impl.auth.DigestSchemeFactory
-org.apache.http.impl.client.AbstractAuthenticationHandler
-org.apache.http.impl.client.AbstractHttpClient
-org.apache.http.impl.client.BasicCredentialsProvider
-org.apache.http.impl.client.ClientParamsStack
-org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy
-org.apache.http.impl.client.DefaultHttpClient
-org.apache.http.impl.client.DefaultHttpRequestRetryHandler
-org.apache.http.impl.client.DefaultProxyAuthenticationHandler
-org.apache.http.impl.client.DefaultRedirectHandler
-org.apache.http.impl.client.DefaultRequestDirector
-org.apache.http.impl.client.DefaultTargetAuthenticationHandler
-org.apache.http.impl.client.DefaultUserTokenHandler
org.apache.http.impl.client.EntityEnclosingRequestWrapper
org.apache.http.impl.client.RequestWrapper
-org.apache.http.impl.client.RoutedRequest
-org.apache.http.impl.client.TunnelRefusedException
-org.apache.http.impl.conn.AbstractClientConnAdapter
-org.apache.http.impl.conn.AbstractPoolEntry
-org.apache.http.impl.conn.AbstractPooledConnAdapter
-org.apache.http.impl.conn.DefaultClientConnection
-org.apache.http.impl.conn.DefaultClientConnectionOperator
-org.apache.http.impl.conn.DefaultResponseParser
-org.apache.http.impl.conn.IdleConnectionHandler
-org.apache.http.impl.conn.IdleConnectionHandler$TimeValues
-org.apache.http.impl.conn.ProxySelectorRoutePlanner
-org.apache.http.impl.conn.tsccm.AbstractConnPool
-org.apache.http.impl.conn.tsccm.BasicPoolEntry
-org.apache.http.impl.conn.tsccm.BasicPoolEntryRef
-org.apache.http.impl.conn.tsccm.BasicPooledConnAdapter
-org.apache.http.impl.conn.tsccm.ConnPoolByRoute
-org.apache.http.impl.conn.tsccm.ConnPoolByRoute$1
-org.apache.http.impl.conn.tsccm.PoolEntryRequest
-org.apache.http.impl.conn.tsccm.RefQueueHandler
-org.apache.http.impl.conn.tsccm.RefQueueWorker
-org.apache.http.impl.conn.tsccm.RouteSpecificPool
-org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager
-org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager$1
-org.apache.http.impl.conn.tsccm.WaitingThreadAborter
-org.apache.http.impl.cookie.BestMatchSpecFactory
-org.apache.http.impl.cookie.BrowserCompatSpecFactory
org.apache.http.impl.cookie.DateParseException
-org.apache.http.impl.cookie.NetscapeDraftSpecFactory
-org.apache.http.impl.cookie.RFC2109SpecFactory
-org.apache.http.impl.cookie.RFC2965SpecFactory
-org.apache.http.impl.entity.EntityDeserializer
-org.apache.http.impl.entity.EntitySerializer
-org.apache.http.impl.entity.LaxContentLengthStrategy
-org.apache.http.impl.entity.StrictContentLengthStrategy
-org.apache.http.impl.io.AbstractMessageParser
-org.apache.http.impl.io.AbstractMessageWriter
-org.apache.http.impl.io.AbstractSessionInputBuffer
-org.apache.http.impl.io.AbstractSessionOutputBuffer
-org.apache.http.impl.io.ChunkedInputStream
-org.apache.http.impl.io.ContentLengthOutputStream
-org.apache.http.impl.io.HttpRequestWriter
-org.apache.http.impl.io.HttpTransportMetricsImpl
-org.apache.http.impl.io.SocketInputBuffer
-org.apache.http.impl.io.SocketOutputBuffer
-org.apache.http.io.HttpMessageParser
-org.apache.http.io.HttpMessageWriter
-org.apache.http.io.HttpTransportMetrics
-org.apache.http.io.SessionInputBuffer
-org.apache.http.io.SessionOutputBuffer
+org.apache.http.impl.cookie.DateUtils
org.apache.http.message.AbstractHttpMessage
org.apache.http.message.BasicHeader
-org.apache.http.message.BasicHeaderElement
-org.apache.http.message.BasicHeaderElementIterator
-org.apache.http.message.BasicHeaderValueParser
org.apache.http.message.BasicHttpResponse
-org.apache.http.message.BasicLineFormatter
-org.apache.http.message.BasicLineParser
-org.apache.http.message.BasicListHeaderIterator
org.apache.http.message.BasicNameValuePair
-org.apache.http.message.BasicRequestLine
org.apache.http.message.BasicStatusLine
-org.apache.http.message.BufferedHeader
org.apache.http.message.HeaderGroup
-org.apache.http.message.HeaderValueParser
-org.apache.http.message.LineFormatter
-org.apache.http.message.LineParser
-org.apache.http.message.ParserCursor
org.apache.http.params.AbstractHttpParams
org.apache.http.params.BasicHttpParams
org.apache.http.params.CoreConnectionPNames
-org.apache.http.params.CoreProtocolPNames
org.apache.http.params.HttpConnectionParams
org.apache.http.params.HttpParams
-org.apache.http.params.HttpProtocolParams
-org.apache.http.protocol.BasicHttpContext
-org.apache.http.protocol.BasicHttpProcessor
-org.apache.http.protocol.HTTP
org.apache.http.protocol.HttpContext
-org.apache.http.protocol.HttpProcessor
-org.apache.http.protocol.HttpRequestExecutor
-org.apache.http.protocol.HttpRequestInterceptorList
-org.apache.http.protocol.HttpResponseInterceptorList
-org.apache.http.protocol.RequestConnControl
-org.apache.http.protocol.RequestContent
-org.apache.http.protocol.RequestExpectContinue
-org.apache.http.protocol.RequestTargetHost
-org.apache.http.protocol.RequestUserAgent
-org.apache.http.util.ByteArrayBuffer
-org.apache.http.util.CharArrayBuffer
-org.apache.http.util.LangUtils
-org.ccil.cowan.tagsoup.AttributesImpl
-org.ccil.cowan.tagsoup.AutoDetector
-org.ccil.cowan.tagsoup.Element
-org.ccil.cowan.tagsoup.ElementType
-org.ccil.cowan.tagsoup.HTMLModels
-org.ccil.cowan.tagsoup.HTMLScanner
-org.ccil.cowan.tagsoup.HTMLSchema
-org.ccil.cowan.tagsoup.Parser
-org.ccil.cowan.tagsoup.Parser$1
-org.ccil.cowan.tagsoup.ScanHandler
-org.ccil.cowan.tagsoup.Scanner
-org.ccil.cowan.tagsoup.Schema
org.json.JSON
org.json.JSONArray
org.json.JSONException
@@ -3817,9 +3954,218 @@
org.xml.sax.SAXNotRecognizedException
org.xml.sax.SAXNotSupportedException
org.xml.sax.XMLReader
-org.xml.sax.ext.LexicalHandler
org.xml.sax.helpers.DefaultHandler
org.xmlpull.v1.XmlPullParser
org.xmlpull.v1.XmlPullParserException
org.xmlpull.v1.XmlSerializer
+sun.misc.Cleaner
+sun.misc.CompoundEnumeration
+sun.misc.FormattedFloatingDecimal
+sun.misc.FormattedFloatingDecimal$1
+sun.misc.FormattedFloatingDecimal$Form
+sun.misc.FpUtils
+sun.misc.Hashing
+sun.misc.IOUtils
+sun.misc.IoTrace
+sun.misc.REException
sun.misc.Unsafe
+sun.misc.VM
+sun.misc.Version
+sun.net.ConnectionResetException
+sun.net.NetHooks
+sun.net.NetProperties
+sun.net.NetProperties$1
+sun.net.spi.DefaultProxySelector
+sun.net.spi.DefaultProxySelector$1
+sun.net.spi.DefaultProxySelector$2
+sun.net.spi.DefaultProxySelector$NonProxyInfo
+sun.net.spi.nameservice.NameService
+sun.net.util.IPAddressUtil
+sun.net.www.ParseUtil
+sun.net.www.protocol.file.Handler
+sun.net.www.protocol.jar.Handler
+sun.nio.ch.DatagramChannelImpl
+sun.nio.ch.DatagramDispatcher
+sun.nio.ch.DirectBuffer
+sun.nio.ch.EPollArrayWrapper
+sun.nio.ch.FileChannelImpl
+sun.nio.ch.FileChannelImpl$Unmapper
+sun.nio.ch.FileDispatcher
+sun.nio.ch.FileDispatcherImpl
+sun.nio.ch.FileKey
+sun.nio.ch.FileLockImpl
+sun.nio.ch.FileLockTable
+sun.nio.ch.IOStatus
+sun.nio.ch.IOUtil
+sun.nio.ch.InheritedChannel
+sun.nio.ch.Interruptible
+sun.nio.ch.NativeDispatcher
+sun.nio.ch.NativeThread
+sun.nio.ch.NativeThreadSet
+sun.nio.ch.Net
+sun.nio.ch.SelChImpl
+sun.nio.ch.ServerSocketChannelImpl
+sun.nio.ch.SharedFileLockTable
+sun.nio.ch.SharedFileLockTable$FileLockReference
+sun.nio.ch.SocketChannelImpl
+sun.nio.ch.Util
+sun.nio.ch.Util$1
+sun.nio.cs.ArrayDecoder
+sun.nio.cs.ArrayEncoder
+sun.nio.cs.StreamDecoder
+sun.nio.cs.StreamEncoder
+sun.nio.cs.ThreadLocalCoders
+sun.nio.cs.ThreadLocalCoders$1
+sun.nio.cs.ThreadLocalCoders$2
+sun.nio.cs.ThreadLocalCoders$Cache
+sun.reflect.annotation.AnnotationType
+sun.security.action.GetBooleanAction
+sun.security.action.GetPropertyAction
+sun.security.ec.ECKeyFactory
+sun.security.ec.ECKeyFactory$1
+sun.security.ec.ECKeyFactory$2
+sun.security.ec.ECParameters
+sun.security.ec.NamedCurve
+sun.security.jca.GetInstance
+sun.security.jca.GetInstance$Instance
+sun.security.jca.ProviderConfig
+sun.security.jca.ProviderConfig$2
+sun.security.jca.ProviderList
+sun.security.jca.ProviderList$1
+sun.security.jca.ProviderList$2
+sun.security.jca.ProviderList$3
+sun.security.jca.ProviderList$ServiceList
+sun.security.jca.ProviderList$ServiceList$1
+sun.security.jca.Providers
+sun.security.jca.ServiceId
+sun.security.pkcs.PKCS9Attribute
+sun.security.pkcs.ParsingException
+sun.security.pkcs.SignerInfo
+sun.security.provider.CertPathProvider
+sun.security.provider.X509Factory
+sun.security.provider.certpath.AdaptableX509CertSelector
+sun.security.provider.certpath.AlgorithmChecker
+sun.security.provider.certpath.BasicChecker
+sun.security.provider.certpath.CertPathHelper
+sun.security.provider.certpath.ConstraintsChecker
+sun.security.provider.certpath.KeyChecker
+sun.security.provider.certpath.PKIX
+sun.security.provider.certpath.PKIX$ValidatorParams
+sun.security.provider.certpath.PKIXCertPathValidator
+sun.security.provider.certpath.PKIXMasterCertPathValidator
+sun.security.provider.certpath.PolicyChecker
+sun.security.provider.certpath.PolicyNodeImpl
+sun.security.provider.certpath.UntrustedChecker
+sun.security.util.BitArray
+sun.security.util.ByteArrayLexOrder
+sun.security.util.ByteArrayTagOrder
+sun.security.util.Cache
+sun.security.util.Cache$EqualByteArray
+sun.security.util.Debug
+sun.security.util.DerEncoder
+sun.security.util.DerIndefLenConverter
+sun.security.util.DerInputBuffer
+sun.security.util.DerInputStream
+sun.security.util.DerOutputStream
+sun.security.util.DerValue
+sun.security.util.DisabledAlgorithmConstraints
+sun.security.util.DisabledAlgorithmConstraints$1
+sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraint
+sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraint$Operator
+sun.security.util.DisabledAlgorithmConstraints$KeySizeConstraints
+sun.security.util.KeyUtil
+sun.security.util.Length
+sun.security.util.MemoryCache
+sun.security.util.MemoryCache$CacheEntry
+sun.security.util.MemoryCache$SoftCacheEntry
+sun.security.util.ObjectIdentifier
+sun.security.util.UntrustedCertificates
+sun.security.x509.AVA
+sun.security.x509.AVAKeyword
+sun.security.x509.AccessDescription
+sun.security.x509.AlgorithmId
+sun.security.x509.AuthorityInfoAccessExtension
+sun.security.x509.AuthorityKeyIdentifierExtension
+sun.security.x509.BasicConstraintsExtension
+sun.security.x509.CRLDistributionPointsExtension
+sun.security.x509.CRLNumberExtension
+sun.security.x509.CRLReasonCodeExtension
+sun.security.x509.CertAttrSet
+sun.security.x509.CertificateAlgorithmId
+sun.security.x509.CertificateExtensions
+sun.security.x509.CertificateIssuerExtension
+sun.security.x509.CertificatePoliciesExtension
+sun.security.x509.CertificatePolicyId
+sun.security.x509.CertificateSerialNumber
+sun.security.x509.CertificateValidity
+sun.security.x509.CertificateVersion
+sun.security.x509.CertificateX509Key
+sun.security.x509.DNSName
+sun.security.x509.DeltaCRLIndicatorExtension
+sun.security.x509.DistributionPoint
+sun.security.x509.ExtendedKeyUsageExtension
+sun.security.x509.Extension
+sun.security.x509.FreshestCRLExtension
+sun.security.x509.GeneralName
+sun.security.x509.GeneralNameInterface
+sun.security.x509.GeneralNames
+sun.security.x509.InhibitAnyPolicyExtension
+sun.security.x509.IssuerAlternativeNameExtension
+sun.security.x509.IssuingDistributionPointExtension
+sun.security.x509.KeyIdentifier
+sun.security.x509.KeyUsageExtension
+sun.security.x509.NameConstraintsExtension
+sun.security.x509.NetscapeCertTypeExtension
+sun.security.x509.OCSPNoCheckExtension
+sun.security.x509.OIDMap
+sun.security.x509.OIDMap$OIDInfo
+sun.security.x509.PKIXExtensions
+sun.security.x509.PolicyConstraintsExtension
+sun.security.x509.PolicyInformation
+sun.security.x509.PolicyMappingsExtension
+sun.security.x509.PrivateKeyUsageExtension
+sun.security.x509.RDN
+sun.security.x509.SerialNumber
+sun.security.x509.SubjectAlternativeNameExtension
+sun.security.x509.SubjectInfoAccessExtension
+sun.security.x509.SubjectKeyIdentifierExtension
+sun.security.x509.URIName
+sun.security.x509.X500Name
+sun.security.x509.X500Name$1
+sun.security.x509.X509AttributeName
+sun.security.x509.X509CertImpl
+sun.security.x509.X509CertInfo
+sun.security.x509.X509Key
+sun.util.LocaleServiceProviderPool
+sun.util.LocaleServiceProviderPool$1
+sun.util.calendar.AbstractCalendar
+sun.util.calendar.BaseCalendar
+sun.util.calendar.BaseCalendar$Date
+sun.util.calendar.CalendarDate
+sun.util.calendar.CalendarSystem
+sun.util.calendar.CalendarUtils
+sun.util.calendar.Gregorian
+sun.util.calendar.Gregorian$Date
+sun.util.calendar.JulianCalendar
+sun.util.calendar.LocalGregorianCalendar
+sun.util.locale.BaseLocale
+sun.util.locale.BaseLocale$Cache
+sun.util.locale.BaseLocale$Key
+sun.util.locale.Extension
+sun.util.locale.InternalLocaleBuilder
+sun.util.locale.InternalLocaleBuilder$CaseInsensitiveChar
+sun.util.locale.LanguageTag
+sun.util.locale.LocaleExtensions
+sun.util.locale.LocaleObjectCache
+sun.util.locale.LocaleObjectCache$CacheEntry
+sun.util.locale.LocaleSyntaxException
+sun.util.locale.LocaleUtils
+sun.util.locale.ParseStatus
+sun.util.locale.StringTokenIterator
+sun.util.locale.UnicodeLocaleExtension
+sun.util.logging.LoggingProxy
+sun.util.logging.LoggingSupport
+sun.util.logging.LoggingSupport$1
+sun.util.logging.PlatformLogger
+sun.util.logging.PlatformLogger$1
+sun.util.logging.PlatformLogger$Level
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 4be6833..388c8b7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2162,8 +2162,13 @@
mIntent = new Intent().setComponent(mComponentName);
mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.accessibility_binding_label);
- mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
- mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
+ final long idendtity = Binder.clearCallingIdentity();
+ try {
+ mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+ mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
+ } finally {
+ Binder.restoreCallingIdentity(idendtity);
+ }
}
setDynamicallyConfigurableProperties(accessibilityServiceInfo);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 9e6cd00..3ecff40 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -467,17 +467,18 @@
if (mCurrentState == STATE_GESTURE_DETECTING) {
endGestureDetection();
} else if (mCurrentState == STATE_TOUCH_EXPLORING) {
- final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
- final int pointerIdBits = (1 << pointerId);
+ // If the finger is still moving, pass the event on.
+ if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
+ final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
+ final int pointerIdBits = (1 << pointerId);
- // Cache the event until we discern exploration from gesturing.
- mSendHoverEnterAndMoveDelayed.addEvent(event);
-
- // We have just decided that the user is touch,
- // exploring so start sending events.
- mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
- mSendHoverExitDelayed.cancel();
- sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+ // We have just decided that the user is touch,
+ // exploring so start sending events.
+ mSendHoverEnterAndMoveDelayed.addEvent(event);
+ mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
+ mSendHoverExitDelayed.cancel();
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+ }
}
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 4646f3c..2b52799 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -159,7 +159,7 @@
reloadWidgetsMaskedStateForUser(userId);
} else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
synchronized (mLock) {
- reloadWidgetQuietModeMaskedStateLocked(userId);
+ reloadWidgetProfileUnavailableMaskedStateLocked(userId);
}
} else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) {
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
@@ -432,7 +432,7 @@
/**
* Reload all widgets' masked state for the given user and its associated profiles, including
- * due to quiet mode and package suspension.
+ * due to user not being available and package suspension.
*/
private void reloadWidgetsMaskedStateForUser(int userId) {
if (!mUserManager.isUserUnlocked(userId)) return;
@@ -442,7 +442,7 @@
if (profiles != null) {
for (int i = 0; i < profiles.size(); i++) {
UserInfo user = profiles.get(i);
- reloadWidgetQuietModeMaskedStateLocked(user.id);
+ reloadWidgetProfileUnavailableMaskedStateLocked(user.id);
reloadWidgetPackageSuspensionMaskedStateLocked(user.id);
}
}
@@ -450,17 +450,18 @@
}
/**
- * Mask/unmask widgets in the given profile, depending on the quiet state of the profile.
+ * Mask/unmask widgets in the given profile, depending on the quiet state
+ * or locked state of the profile.
*/
- private void reloadWidgetQuietModeMaskedStateLocked(int profileId) {
- if (!mUserManager.isUserUnlocked(profileId)) return;
+ private void reloadWidgetProfileUnavailableMaskedStateLocked(int profileId) {
final long identity = Binder.clearCallingIdentity();
try {
- UserInfo user = mUserManager.getUserInfo(profileId);
- if (!user.isManagedProfile()) {
+ if (!isProfileWithUnlockedParent(profileId)) {
return;
}
- boolean shouldMask = user.isQuietModeEnabled();
+ UserInfo user = mUserManager.getUserInfo(profileId);
+ boolean shouldMask = user.isQuietModeEnabled() ||
+ !mUserManager.isUserUnlocked(user.getUserHandle());
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
Provider provider = mProviders.get(i);
@@ -468,7 +469,7 @@
if (providerUserId != profileId) {
continue;
}
- if (provider.setMaskedByQuietProfileLocked(shouldMask)) {
+ if (provider.setMaskedByProfileUnavailabledLocked(shouldMask)) {
if (provider.isMaskedLocked()) {
maskWidgetsViewsLocked(provider);
} else {
@@ -537,8 +538,8 @@
}
}
- private void maskWidgetsViewsLocked(Provider provider) {
- Bitmap iconBitmap = null;
+ private Bitmap createMaskedWidgetBitmap(Provider provider) {
+ final long identity = Binder.clearCallingIdentity();
try {
// Load the unbadged application icon and pass it to the widget to appear on
// the masked view.
@@ -548,11 +549,20 @@
PackageManager pm = userContext.getPackageManager();
Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm);
// Create a bitmap of the icon which is what the widget's remoteview requires.
- iconBitmap = mIconUtilities.createIconBitmap(icon);
+ return mIconUtilities.createIconBitmap(icon);
} catch (NameNotFoundException e) {
Slog.e(TAG, "Fail to get application icon", e);
// Provider package removed, no need to mask its views as its state will be
// purged very soon.
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private void maskWidgetsViewsLocked(Provider provider) {
+ Bitmap iconBitmap = createMaskedWidgetBitmap(provider);
+ if (iconBitmap == null) {
return;
}
@@ -2320,7 +2330,7 @@
final PackageManager pm = mContext.getPackageManager();
final int userId = UserHandle.getUserId(providerId.uid);
final ApplicationInfo app = pm.getApplicationInfoAsUser(activityInfo.packageName,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
+ 0, userId);
resources = pm.getResourcesForApplication(app);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2423,9 +2433,16 @@
int flags = PackageManager.GET_META_DATA;
// We really need packages to be around and parsed to know if they
- // provide widgets, and we only load widgets after user is unlocked.
+ // provide widgets.
flags |= PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+ // Widget hosts that are non-crypto aware may be hosting widgets
+ // from a profile that is still locked, so let them see those
+ // widgets.
+ if (isProfileWithUnlockedParent(userId)) {
+ flags |= PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+ }
+
// Widgets referencing shared libraries need to have their
// dependencies loaded.
flags |= PackageManager.GET_SHARED_LIBRARY_FILES;
@@ -2443,6 +2460,7 @@
private void onUserUnlocked(int userId) {
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
+ reloadWidgetsMaskedStateForUser(userId);
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
@@ -2580,6 +2598,17 @@
mWidgetPackages.put(userId, packages = new ArraySet<String>());
}
packages.add(widget.provider.info.provider.getPackageName());
+
+ // If we are adding a widget it might be for a provider that
+ // is currently masked, if so mask the widget.
+ if (widget.provider.isMaskedLocked()) {
+ Bitmap bitmap = createMaskedWidgetBitmap(widget.provider);
+ if (bitmap != null) {
+ widget.replaceWithMaskedViewsLocked(mContext, bitmap);
+ }
+ } else {
+ widget.clearMaskedViewsLocked();
+ }
}
/**
@@ -3277,6 +3306,18 @@
}
}
+ private boolean isProfileWithUnlockedParent(int userId) {
+ UserInfo userInfo = mUserManager.getUserInfo(userId);
+ if (userInfo != null && userInfo.isManagedProfile()) {
+ UserInfo parentInfo = mUserManager.getProfileParent(userId);
+ if (parentInfo != null
+ && mUserManager.isUserUnlocked(parentInfo.getUserHandle())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private final class CallbackHandler extends Handler {
public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1;
public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2;
@@ -3554,7 +3595,7 @@
PendingIntent broadcast;
boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
- boolean maskedByQuietProfile;
+ boolean maskedByProfileUnavailable;
boolean maskedBySuspendedPackage;
int tag = TAG_UNDEFINED; // for use while saving state (the index)
@@ -3587,9 +3628,9 @@
}
// returns true if the provider's masked state is changed as a result
- public boolean setMaskedByQuietProfileLocked(boolean masked) {
+ public boolean setMaskedByProfileUnavailabledLocked(boolean masked) {
boolean oldMaskedState = isMaskedLocked();
- maskedByQuietProfile = masked;
+ maskedByProfileUnavailable = masked;
return isMaskedLocked() != oldMaskedState;
}
@@ -3601,7 +3642,7 @@
}
public boolean isMaskedLocked() {
- return maskedByQuietProfile || maskedBySuspendedPackage;
+ return maskedByProfileUnavailable || maskedBySuspendedPackage;
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index eaee1d3..e32d89c 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.backup;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
+
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppGlobals;
@@ -191,7 +193,8 @@
// 1 : initial release
// 2 : no format change per se; version bump to facilitate PBKDF2 version skew detection
// 3 : introduced "_meta" metadata file; no other format change per se
- static final int BACKUP_FILE_VERSION = 3;
+ // 4 : added support for new device-encrypted storage locations
+ static final int BACKUP_FILE_VERSION = 4;
static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
static final int BACKUP_PW_FILE_VERSION = 2;
static final String BACKUP_METADATA_FILENAME = "_meta";
@@ -347,13 +350,13 @@
}
@Override
- public void onBootPhase(int phase) {
- if (phase == PHASE_SYSTEM_SERVICES_READY) {
- sInstance.initialize(UserHandle.USER_SYSTEM);
- } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ public void onUnlockUser(int userId) {
+ if (userId == UserHandle.USER_SYSTEM) {
+ sInstance.initialize(userId);
+
ContentResolver r = sInstance.mContext.getContentResolver();
- boolean areEnabled = Settings.Secure.getInt(r,
- Settings.Secure.BACKUP_ENABLED, 0) != 0;
+ boolean areEnabled = Settings.Secure.getIntForUser(r,
+ Settings.Secure.BACKUP_ENABLED, 0, userId) != 0;
try {
sInstance.setBackupEnabled(areEnabled);
} catch (RemoteException e) {
@@ -4928,7 +4931,9 @@
continue;
}
- headBusy = mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
+ final int privFlags = appInfo.applicationInfo.privateFlags;
+ headBusy = (privFlags & PRIVATE_FLAG_BACKUP_IN_FOREGROUND) == 0
+ && mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
if (headBusy) {
final long nextEligible = System.currentTimeMillis()
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 91f58c56..32f2d59 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -31,6 +31,7 @@
import java.util.List;
import java.util.Map;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
@@ -67,6 +68,7 @@
import com.android.internal.os.Zygote;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import libcore.util.EmptyArray;
@@ -103,9 +105,10 @@
}
};
- final SparseArray<UidState> mUidStates = new SparseArray<>();
+ private final SparseArray<UidState> mUidStates = new SparseArray<>();
- private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
+ /** These are app op restrictions imposed per user from various parties */
+ private final ArrayMap<IBinder, SparseArray<boolean[]>> mOpUserRestrictions = new ArrayMap<>();
private static final class UidState {
public final int uid;
@@ -1263,17 +1266,21 @@
private boolean isOpRestricted(int uid, int code, String packageName) {
int userHandle = UserHandle.getUserId(uid);
- boolean[] opRestrictions = mOpRestrictions.get(userHandle);
- if ((opRestrictions != null) && opRestrictions[code]) {
- if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
- synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
- if ((ops != null) && ops.isPrivileged) {
- return false;
+ final int restrictionSetCount = mOpUserRestrictions.size();
+ for (int i = 0; i < restrictionSetCount; i++) {
+ SparseArray<boolean[]> perUserRestrictions = mOpUserRestrictions.valueAt(i);
+ boolean[] opRestrictions = perUserRestrictions.get(userHandle);
+ if (opRestrictions != null && opRestrictions[code]) {
+ if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
+ synchronized (this) {
+ Ops ops = getOpsLocked(uid, packageName, true);
+ if ((ops != null) && ops.isPrivileged) {
+ return false;
+ }
}
}
+ return true;
}
- return true;
}
return false;
}
@@ -2049,27 +2056,123 @@
}
@Override
- public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException {
+ public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
checkSystemUid("setUserRestrictions");
- boolean[] opRestrictions = mOpRestrictions.get(userHandle);
- if (opRestrictions == null) {
- opRestrictions = new boolean[AppOpsManager._NUM_OP];
- mOpRestrictions.put(userHandle, opRestrictions);
- }
+ Preconditions.checkNotNull(token);
+ final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
for (int i = 0; i < opRestrictions.length; ++i) {
String restriction = AppOpsManager.opToRestriction(i);
- if (restriction != null) {
- opRestrictions[i] = restrictions.getBoolean(restriction, false);
- } else {
- opRestrictions[i] = false;
+ final boolean restricted = restriction != null
+ && restrictions.getBoolean(restriction, false);
+ setUserRestrictionNoCheck(i, restricted, token, userHandle);
+ }
+ }
+
+ @Override
+ public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle) {
+ if (Binder.getCallingPid() != Process.myPid()) {
+ mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
+ Binder.getCallingPid(), Binder.getCallingUid(), null);
+ }
+ if (userHandle != UserHandle.getCallingUserId()) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission
+ .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(Manifest.permission
+ .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
+ + " INTERACT_ACROSS_USERS to interact cross user ");
}
}
+ verifyIncomingOp(code);
+ Preconditions.checkNotNull(token);
+ setUserRestrictionNoCheck(code, restricted, token, userHandle);
+ }
+
+ private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
+ int userHandle) {
+ final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
+ if (opRestrictions[code] == restricted) {
+ return;
+ }
+ opRestrictions[code] = restricted;
+ if (!restricted) {
+ pruneUserRestrictionsForToken(token, userHandle);
+ }
+
+ final ArrayList<Callback> clonedCallbacks;
+ synchronized (this) {
+ ArrayList<Callback> callbacks = mOpModeWatchers.get(code);
+ if (callbacks == null) {
+ return;
+ }
+ clonedCallbacks = new ArrayList<>(callbacks);
+ }
+
+ // There are components watching for mode changes such as window manager
+ // and location manager which are in our process. The callbacks in these
+ // components may require permissions our remote caller does not have.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final int callbackCount = clonedCallbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ Callback callback = clonedCallbacks.get(i);
+ try {
+ callback.mCallback.opChanged(code, -1, null);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error dispatching op op change", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
public void removeUser(int userHandle) throws RemoteException {
checkSystemUid("removeUser");
- mOpRestrictions.remove(userHandle);
+ final int tokenCount = mOpUserRestrictions.size();
+ for (int i = tokenCount - 1; i >= 0; i--) {
+ SparseArray<boolean[]> opRestrictions = mOpUserRestrictions.valueAt(i);
+ if (opRestrictions != null) {
+ opRestrictions.remove(userHandle);
+ if (opRestrictions.size() <= 0) {
+ mOpUserRestrictions.removeAt(i);
+ }
+ }
+ }
+ }
+
+
+ private void pruneUserRestrictionsForToken(IBinder token, int userHandle) {
+ SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token);
+ if (perTokenRestrictions != null) {
+ final boolean[] opRestrictions = perTokenRestrictions.get(userHandle);
+ if (opRestrictions != null) {
+ for (boolean restriction : opRestrictions) {
+ if (restriction) {
+ return;
+ }
+ }
+ perTokenRestrictions.remove(userHandle);
+ if (perTokenRestrictions.size() <= 0) {
+ mOpUserRestrictions.remove(token);
+ }
+ }
+ }
+ }
+
+ private boolean[] getOrCreateUserRestrictionsForToken(IBinder token, int userHandle) {
+ SparseArray<boolean[]> perTokenRestrictions = mOpUserRestrictions.get(token);
+ if (perTokenRestrictions == null) {
+ perTokenRestrictions = new SparseArray<>();
+ mOpUserRestrictions.put(token, perTokenRestrictions);
+ }
+ boolean[] opRestrictions = perTokenRestrictions.get(userHandle);
+ if (opRestrictions == null) {
+ opRestrictions = new boolean[AppOpsManager._NUM_OP];
+ perTokenRestrictions.put(userHandle, opRestrictions);
+ }
+ return opRestrictions;
}
private void checkSystemUid(String function) {
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
new file mode 100644
index 0000000..cc21e99
--- /dev/null
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.CpuUsageInfo;
+import android.os.IHardwarePropertiesManager;
+
+import java.util.Arrays;
+
+/**
+ * Service for {@link HardwarePropertiesManager}
+ */
+public class HardwarePropertiesManagerService extends IHardwarePropertiesManager.Stub {
+
+ private static native void nativeInit();
+
+ private static native float[] nativeGetFanSpeeds();
+ private static native float[] nativeGetDeviceTemperatures(int type);
+ private static native CpuUsageInfo[] nativeGetCpuUsages();
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+
+ public HardwarePropertiesManagerService(Context context) {
+ mContext = context;
+ synchronized (mLock) {
+ nativeInit();
+ }
+ }
+
+ @Override
+ public float[] getDeviceTemperatures(String callingPackage, int type) throws SecurityException {
+ enforceHardwarePropertiesRetrievalAllowed(callingPackage);
+ synchronized (mLock) {
+ return nativeGetDeviceTemperatures(type);
+ }
+ }
+
+ @Override
+ public CpuUsageInfo[] getCpuUsages(String callingPackage) throws SecurityException {
+ enforceHardwarePropertiesRetrievalAllowed(callingPackage);
+ synchronized (mLock) {
+ return nativeGetCpuUsages();
+ }
+ }
+
+ @Override
+ public float[] getFanSpeeds(String callingPackage) throws SecurityException {
+ enforceHardwarePropertiesRetrievalAllowed(callingPackage);
+ synchronized (mLock) {
+ return nativeGetFanSpeeds();
+ }
+ }
+
+ /**
+ * Throws SecurityException if the calling package is not allowed to retrieve information
+ * provided by the service.
+ *
+ * @param callingPackage The calling package name.
+ *
+ * @throws SecurityException if a non profile or device owner tries to retrieve information
+ * provided by the service.
+ */
+ private void enforceHardwarePropertiesRetrievalAllowed(String callingPackage)
+ throws SecurityException {
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ final int uid = pm.getPackageUid(callingPackage, 0);
+ if (Binder.getCallingUid() != uid) {
+ throw new SecurityException("The caller has faked the package name.");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new SecurityException("The caller has faked the package name.");
+ }
+
+ final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+ if (!dpm.isDeviceOwnerApp(callingPackage) && !dpm.isProfileOwnerApp(callingPackage)) {
+ throw new SecurityException("The caller is not a device or profile owner.");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 507ac22..d1de7e5 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -61,7 +61,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
@@ -190,6 +189,7 @@
private InputMethodFileManager mFileManager;
private final HardKeyboardListener mHardKeyboardListener;
private final AppOpsManager mAppOpsManager;
+ private final UserManager mUserManager;
final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1, -1);
@@ -781,6 +781,27 @@
mService.systemRunning(statusBarService);
}
}
+
+ @Override
+ public void onUnlockUser(int userHandle) {
+ mService.onUnlockUser(userHandle);
+ }
+ }
+
+ public void onUnlockUser(int userId) {
+ synchronized(mMethodMap) {
+ final int currentUserId = mSettings.getCurrentUserId();
+ if (DEBUG) {
+ Slog.d(TAG, "onUnlockUser: userId=" + userId + " curUserId=" + currentUserId);
+ }
+ if (userId != currentUserId) {
+ return;
+ }
+ mSettings.switchCurrentUser(currentUserId, !mSystemReady);
+ // We need to rebuild IMEs.
+ buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
+ updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+ }
}
public InputMethodManagerService(Context context) {
@@ -800,6 +821,7 @@
}
}, true /*asyncHandler*/);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+ mUserManager = mContext.getSystemService(UserManager.class);
mHardKeyboardListener = new HardKeyboardListener();
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_INPUT_METHODS);
@@ -859,39 +881,6 @@
mSettings = new InputMethodSettings(
mRes, context.getContentResolver(), mMethodMap, mMethodList, userId, !mSystemReady);
- // Let the package manager query which are the default imes
- // as they get certain permissions granted by default.
- PackageManagerInternal packageManagerInternal = LocalServices.getService(
- PackageManagerInternal.class);
- packageManagerInternal.setImePackagesProvider(
- new PackageManagerInternal.PackagesProvider() {
- @Override
- public String[] getPackages(int userId) {
- synchronized (mMethodMap) {
- final int currentUserId = mSettings.getCurrentUserId();
- // TODO: We are switching the current user id in the settings
- // object to query it and then revert the user id. Ideally, we
- // should call a API in settings with the user id as an argument.
- mSettings.switchCurrentUser(userId, true /* copyOnWrite */);
- List<InputMethodInfo> imes = mSettings
- .getEnabledInputMethodListLocked();
- String[] packageNames = null;
- if (imes != null) {
- final int imeCount = imes.size();
- packageNames = new String[imeCount];
- for (int i = 0; i < imeCount; i++) {
- InputMethodInfo ime = imes.get(i);
- packageNames[i] = ime.getPackageName();
- }
- }
- // If the system is not ready, then we use copy-on-write mode.
- final boolean useCopyOnWriteSettings = !mSystemReady;
- mSettings.switchCurrentUser(currentUserId, useCopyOnWriteSettings);
- return packageNames;
- }
- }
- });
-
updateCurrentProfileIds();
mFileManager = new InputMethodFileManager(mMethodMap, userId);
synchronized (mMethodMap) {
@@ -1006,8 +995,10 @@
// ContentObserver should be registered again when the user is changed
mSettingsObserver.registerContentObserverLocked(newUserId);
- // If the system is not ready, then we use copy-on-write settings.
- final boolean useCopyOnWriteSettings = !mSystemReady;
+ // If the system is not ready or the device is not yed unlocked by the user, then we use
+ // copy-on-write settings.
+ final boolean useCopyOnWriteSettings =
+ !mSystemReady || !mUserManager.isUserUnlocked(newUserId);
mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
updateCurrentProfileIds();
// InputMethodFileManager should be reset when the user is changed
@@ -1036,8 +1027,7 @@
}
void updateCurrentProfileIds() {
- List<UserInfo> profiles = mContext.getSystemService(UserManager.class)
- .getProfiles(mSettings.getCurrentUserId());
+ 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;
@@ -1068,7 +1058,8 @@
if (!mSystemReady) {
mSystemReady = true;
final int currentUserId = mSettings.getCurrentUserId();
- mSettings.switchCurrentUser(currentUserId, false /* copyOnWrite */);
+ mSettings.switchCurrentUser(currentUserId,
+ !mUserManager.isUserUnlocked(currentUserId));
mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
mNotificationManager = mContext.getSystemService(NotificationManager.class);
mStatusBar = statusBar;
@@ -2952,6 +2943,9 @@
// Use for queryIntentServicesAsUser
final PackageManager pm = mContext.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(InputMethod.SERVICE_INTERFACE),
PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 14ddc36..9884a70 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -214,7 +214,7 @@
private int mCurrentUserId = UserHandle.USER_SYSTEM;
private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
- private GnssLocationProvider.GpsSystemInfoProvider mGpsSystemInfoProvider;
+ private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
public LocationManagerService(Context context) {
super();
@@ -462,7 +462,7 @@
// Create a gps location provider
GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
mLocationHandler.getLooper());
- mGpsSystemInfoProvider = gnssProvider.getGpsSystemInfoProvider();
+ mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
addProviderLocked(gnssProvider);
@@ -990,12 +990,12 @@
}
/**
- * Returns the system information of the GPS hardware.
+ * Returns the system information of the GNSS hardware.
*/
@Override
- public int getGpsYearOfHardware() {
+ public int getGnssYearOfHardware() {
if (mGnssNavigationMessageProvider != null) {
- return mGpsSystemInfoProvider.getGpsYearOfHardware();
+ return mGnssSystemInfoProvider.getGnssYearOfHardware();
} else {
return 0;
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index ca1e371..163b9be 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -660,7 +660,12 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- return readUserDataInternal(accounts, account, key);
+ synchronized (accounts.cacheLock) {
+ if (!accountExistsCacheLocked(accounts, account)) {
+ return null;
+ }
+ return readUserDataInternalLocked(accounts, account, key);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1716,44 +1721,58 @@
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
- setUserdataInternal(accounts, account, key, value);
+ synchronized (accounts.cacheLock) {
+ if (!accountExistsCacheLocked(accounts, account)) {
+ return;
+ }
+ setUserdataInternalLocked(accounts, account, key, value);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
}
- private void setUserdataInternal(UserAccounts accounts, Account account, String key,
+ private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) {
+ if (accounts.accountCache.containsKey(account.type)) {
+ for (Account acc : getUserAccountsForCaller().accountCache.get(account.type)) {
+ if (acc.name.equals(account.name)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key,
String value) {
if (account == null || key == null) {
return;
}
- synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- long accountId = getAccountIdLocked(db, account);
- if (accountId < 0) {
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ long accountId = getAccountIdLocked(db, account);
+ if (accountId < 0) {
+ return;
+ }
+ long extrasId = getExtrasIdLocked(db, accountId, key);
+ if (extrasId < 0) {
+ extrasId = insertExtraLocked(db, accountId, key, value);
+ if (extrasId < 0) {
return;
}
- long extrasId = getExtrasIdLocked(db, accountId, key);
- if (extrasId < 0 ) {
- extrasId = insertExtraLocked(db, accountId, key, value);
- if (extrasId < 0) {
- return;
- }
- } else {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_VALUE, value);
- if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
- return;
- }
-
+ } else {
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_VALUE, value);
+ if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
+ return;
}
- writeUserDataIntoCacheLocked(accounts, db, account, key, value);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
+
}
+ writeUserDataIntoCacheLocked(accounts, db, account, key, value);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
}
}
@@ -4788,17 +4807,16 @@
}
}
- protected String readUserDataInternal(UserAccounts accounts, Account account, String key) {
- synchronized (accounts.cacheLock) {
- HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
- if (userDataForAccount == null) {
- // need to populate the cache for this account
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
- accounts.userDataCache.put(account, userDataForAccount);
- }
- return userDataForAccount.get(key);
+ protected String readUserDataInternalLocked(
+ UserAccounts accounts, Account account, String key) {
+ HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
+ if (userDataForAccount == null) {
+ // need to populate the cache for this account
+ final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
+ userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
+ accounts.userDataCache.put(account, userDataForAccount);
}
+ return userDataForAccount.get(key);
}
protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c7f7378..8c04fbc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -273,6 +273,7 @@
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
+import static android.provider.Settings.Global.LENIENT_BACKGROUND_CHECK;
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
import static android.provider.Settings.System.FONT_SCALE;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
@@ -1290,6 +1291,7 @@
String mOrigDebugApp = null;
boolean mOrigWaitForDebugger = false;
boolean mAlwaysFinishActivities = false;
+ boolean mLenientBackgroundCheck = false;
boolean mForceResizableActivities;
boolean mSupportsFreeformWindowManagement;
boolean mSupportsPictureInPicture;
@@ -7490,7 +7492,16 @@
int checkAllowBackgroundLocked(int uid, String packageName, int callingPid) {
UidRecord uidRec = mActiveUids.get(uid);
- if (uidRec == null || uidRec.idle) {
+ if (!mLenientBackgroundCheck) {
+ if (uidRec == null
+ || uidRec.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
+ if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid,
+ packageName) != AppOpsManager.MODE_ALLOWED) {
+ return ActivityManager.APP_START_MODE_DELAYED;
+ }
+ }
+
+ } else if (uidRec == null || uidRec.idle) {
if (callingPid >= 0) {
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
@@ -11376,12 +11387,36 @@
enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
"setAlwaysFinish()");
- Settings.Global.putInt(
- mContext.getContentResolver(),
- Settings.Global.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ Settings.Global.putInt(
+ mContext.getContentResolver(),
+ Settings.Global.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
- synchronized (this) {
- mAlwaysFinishActivities = enabled;
+ synchronized (this) {
+ mAlwaysFinishActivities = enabled;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void setLenientBackgroundCheck(boolean enabled) {
+ enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
+ "setLenientBackgroundCheck()");
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ Settings.Global.putInt(
+ mContext.getContentResolver(),
+ Settings.Global.LENIENT_BACKGROUND_CHECK, enabled ? 1 : 0);
+
+ synchronized (this) {
+ mLenientBackgroundCheck = enabled;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -12278,6 +12313,8 @@
final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
final boolean alwaysFinishActivities =
Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+ final boolean lenientBackgroundCheck =
+ Settings.Global.getInt(resolver, LENIENT_BACKGROUND_CHECK, 0) != 0;
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
final boolean forceResizable = Settings.Global.getInt(
resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
@@ -12295,6 +12332,7 @@
mDebugApp = mOrigDebugApp = debugApp;
mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
mAlwaysFinishActivities = alwaysFinishActivities;
+ mLenientBackgroundCheck = lenientBackgroundCheck;
mForceResizableActivities = forceResizable;
mWindowManager.setForceResizableTasks(mForceResizableActivities);
mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
@@ -14074,8 +14112,9 @@
}
}
if (dumpPackage == null) {
- if (mAlwaysFinishActivities || mController != null) {
+ if (mAlwaysFinishActivities || mLenientBackgroundCheck || mController != null) {
pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
+ + " mLenientBackgroundCheck=" + mLenientBackgroundCheck
+ " mController=" + mController);
}
if (dumpAll) {
@@ -14680,6 +14719,9 @@
case Process.THREAD_GROUP_DEFAULT:
schedGroup = 'F';
break;
+ case Process.THREAD_GROUP_TOP_APP:
+ schedGroup = 'T';
+ break;
default:
schedGroup = '?';
break;
@@ -16957,7 +16999,6 @@
case Process.ROOT_UID:
case Process.SYSTEM_UID:
case Process.PHONE_UID:
- case Process.SHELL_UID:
case Process.BLUETOOTH_UID:
case Process.NFC_UID:
isCallerSystem = true;
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 8c99739..0253976 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -62,6 +62,8 @@
return runUntrackAssociations(pw);
case "is-user-stopped":
return runIsUserStopped(pw);
+ case "lenient-background-check":
+ return runLenientBackgroundCheck(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -152,6 +154,22 @@
return 0;
}
+ int runLenientBackgroundCheck(PrintWriter pw) throws RemoteException {
+ String arg = getNextArg();
+ if (arg != null) {
+ boolean state = Boolean.valueOf(arg) || "1".equals(arg);
+ mInterface.setLenientBackgroundCheck(state);
+ }
+ synchronized (mInternal) {
+ if (mInternal.mLenientBackgroundCheck) {
+ pw.println("Lenient background check enabled");
+ } else {
+ pw.println("Lenient background check disabled");
+ }
+ }
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -203,6 +221,8 @@
pw.println(" Disable and clear association tracking.");
pw.println(" is-user-stopped <USER_ID>");
pw.println(" returns whether <USER_ID> has been stopped or not");
+ pw.println(" lenient-background-check [<true|false>]");
+ pw.println(" optionally controls lenient background check mode, returns current mode.");
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 574b9db..acde10f 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1149,7 +1149,7 @@
|| mService.isSleepingOrShuttingDown()) {
// If we were visible then resumeTopActivities will release resources before
// stopping.
- addToStopping(prev);
+ addToStopping(prev, true /* immediate */);
}
} else {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
@@ -1210,15 +1210,21 @@
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
- private void addToStopping(ActivityRecord r) {
- mStackSupervisor.mStoppingActivities.add(r);
- if (mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE ||
- r.frontOfTask && mTaskHistory.size() <= 1) {
- // If we already have a few activities waiting to stop,
- // then give up on things going idle and start clearing
- // them out. Or if r is the last of activity of the last task the stack
- // will be empty and must be cleared immediately.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "To many pending stops, forcing idle");
+ private void addToStopping(ActivityRecord r, boolean immediate) {
+ if (!mStackSupervisor.mStoppingActivities.contains(r)) {
+ mStackSupervisor.mStoppingActivities.add(r);
+ }
+
+ // If we already have a few activities waiting to stop, then give up
+ // on things going idle and start clearing them out. Or if r is the
+ // last of activity of the last task the stack will be empty and must
+ // be cleared immediately.
+ boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
+ || (r.frontOfTask && mTaskHistory.size() <= 1);
+
+ if (immediate || forceIdle) {
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle="
+ + forceIdle + "immediate=" + immediate);
mStackSupervisor.scheduleIdleLocked();
} else {
mStackSupervisor.checkReadyForSleepLocked();
@@ -1428,10 +1434,12 @@
if (mStackId == DOCKED_STACK_ID) {
// Docked stack is always visible, except in the case where the top running activity
- // task in the focus stack doesn't support any form of resizing.
+ // task in the focus stack doesn't support any form of resizing but we show it for the
+ // home task even though it's not resizable.
final ActivityRecord r = focusedStack.topRunningActivityLocked();
final TaskRecord task = r != null ? r.task : null;
- return task == null || task.canGoInDockedStack() ? STACK_VISIBLE : STACK_INVISIBLE;
+ return task == null || task.canGoInDockedStack() || task.isHomeTask() ? STACK_VISIBLE
+ : STACK_INVISIBLE;
}
// Find the first stack below focused stack that actually got something visible.
@@ -1697,10 +1705,7 @@
if (visibleBehind == r) {
releaseBackgroundResources(r);
} else {
- if (!mStackSupervisor.mStoppingActivities.contains(r)) {
- mStackSupervisor.mStoppingActivities.add(r);
- }
- mStackSupervisor.scheduleIdleLocked();
+ addToStopping(r, true /* immediate */);
}
break;
@@ -3261,7 +3266,7 @@
// finishing until the resumed one becomes visible.
if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
- addToStopping(r);
+ addToStopping(r, false /* immediate */);
}
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to STOPPING: "+ r + " (finish requested)");
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c143474..9562f94 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -400,7 +400,7 @@
// The default minimal size that will be used if the activity doesn't specify its minimal size.
// It will be calculated when the default display gets added.
- private int mDefaultMinimalSizeOfResizeableTask = -1;
+ int mDefaultMinimalSizeOfResizeableTask = -1;
// Whether tasks have moved and we need to rank the tasks before next OOM scoring
private boolean mTaskLayersChanged = true;
@@ -2039,8 +2039,6 @@
return true;
}
- adjustForMinimalTaskDimensions(task, bounds);
-
// If this is a forced resize, let it go through even if the bounds is not changing,
// as we might need a relayout due to surface size change (to/from fullscreen).
final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
@@ -2074,7 +2072,7 @@
// to be relaunched due to configuration change.
boolean kept = true;
if (overrideConfig != null) {
- ActivityRecord r = task.topRunningActivityLocked();
+ final ActivityRecord r = task.topRunningActivityLocked();
if (r != null) {
final ActivityStack stack = task.stack;
kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow);
@@ -2085,44 +2083,12 @@
}
}
}
- mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced);
+ mWindowManager.resizeTask(task.taskId, task.mBounds, task.mOverrideConfig, kept, forced);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
return kept;
}
- private void adjustForMinimalTaskDimensions(TaskRecord task, Rect bounds) {
- if (bounds == null) {
- return;
- }
- int minimalSize = task.mMinimalSize == -1 ? mDefaultMinimalSizeOfResizeableTask
- : task.mMinimalSize;
- final boolean adjustWidth = minimalSize > bounds.width();
- final boolean adjustHeight = minimalSize > bounds.height();
- if (!(adjustWidth || adjustHeight)) {
- return;
- }
- Rect taskBounds = task.mBounds;
- if (adjustWidth) {
- if (taskBounds != null && bounds.right == taskBounds.right) {
- bounds.left = bounds.right - minimalSize;
- } else {
- // Either left bounds match, or neither match, or the previous bounds were
- // fullscreen and we default to keeping left.
- bounds.right = bounds.left + minimalSize;
- }
- }
- if (adjustHeight) {
- if (taskBounds != null && bounds.bottom == taskBounds.bottom) {
- bounds.top = bounds.bottom - minimalSize;
- } else {
- // Either top bounds match, or neither match, or the previous bounds were
- // fullscreen and we default to keeping top.
- bounds.bottom = bounds.top + minimalSize;
- }
- }
- }
-
ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay == null) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 16fd909..37a549a 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -243,6 +243,8 @@
// Bounds of the Task. null for fullscreen tasks.
Rect mBounds = null;
+ private final Rect mTmpStableBounds = new Rect();
+ private final Rect mTmpNonDecorBounds = new Rect();
private final Rect mTmpRect = new Rect();
private final Rect mTmpRect2 = new Rect();
@@ -1313,6 +1315,38 @@
return task;
}
+ private void adjustForMinimalTaskDimensions(Rect bounds) {
+ if (bounds == null) {
+ return;
+ }
+ final int minimalSize = mMinimalSize == -1
+ ? mService.mStackSupervisor.mDefaultMinimalSizeOfResizeableTask : mMinimalSize;
+ final boolean adjustWidth = minimalSize > bounds.width();
+ final boolean adjustHeight = minimalSize > bounds.height();
+ if (!(adjustWidth || adjustHeight)) {
+ return;
+ }
+
+ if (adjustWidth) {
+ if (mBounds != null && bounds.right == mBounds.right) {
+ bounds.left = bounds.right - minimalSize;
+ } else {
+ // Either left bounds match, or neither match, or the previous bounds were
+ // fullscreen and we default to keeping left.
+ bounds.right = bounds.left + minimalSize;
+ }
+ }
+ if (adjustHeight) {
+ if (mBounds != null && bounds.bottom == mBounds.bottom) {
+ bounds.top = bounds.bottom - minimalSize;
+ } else {
+ // Either top bounds match, or neither match, or the previous bounds were
+ // fullscreen and we default to keeping top.
+ bounds.bottom = bounds.top + minimalSize;
+ }
+ }
+ }
+
/**
* Update task's override configuration based on the bounds.
* @param bounds The bounds of the task.
@@ -1345,20 +1379,17 @@
mBounds = null;
mOverrideConfig = Configuration.EMPTY;
} else {
+ mTmpRect.set(bounds);
+ adjustForMinimalTaskDimensions(mTmpRect);
if (mBounds == null) {
- mBounds = new Rect(bounds);
+ mBounds = new Rect(mTmpRect);
} else {
- mBounds.set(bounds);
+ mBounds.set(mTmpRect);
}
if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {
mLastNonFullscreenBounds = mBounds;
}
-
- // Stable insets need to be subtracted because we also subtract it in the fullscreen
- // configuration.
- mTmpRect.set(bounds);
- subtractStableInsets(mTmpRect, insetBounds != null ? insetBounds : mTmpRect);
- mOverrideConfig = calculateOverrideConfig(mTmpRect);
+ mOverrideConfig = calculateOverrideConfig(mTmpRect, insetBounds);
}
if (mFullscreen != oldFullscreen) {
@@ -1368,6 +1399,16 @@
return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
}
+ private void subtractNonDecorInsets(Rect inOutBounds, Rect inInsetBounds) {
+ mTmpRect2.set(inInsetBounds);
+ mService.mWindowManager.subtractNonDecorInsets(mTmpRect2);
+ int leftInset = mTmpRect2.left - inInsetBounds.left;
+ int topInset = mTmpRect2.top - inInsetBounds.top;
+ int rightInset = inInsetBounds.right - mTmpRect2.right;
+ int bottomInset = inInsetBounds.bottom - mTmpRect2.bottom;
+ inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
+ }
+
private void subtractStableInsets(Rect inOutBounds, Rect inInsetBounds) {
mTmpRect2.set(inInsetBounds);
mService.mWindowManager.subtractStableInsets(mTmpRect2);
@@ -1378,23 +1419,39 @@
inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
}
- Configuration calculateOverrideConfig(Rect bounds) {
+ private Configuration calculateOverrideConfig(Rect bounds, Rect insetBounds) {
+ mTmpNonDecorBounds.set(bounds);
+ mTmpStableBounds.set(bounds);
+ subtractNonDecorInsets(
+ mTmpNonDecorBounds, insetBounds != null ? insetBounds : bounds);
+ subtractStableInsets(
+ mTmpStableBounds, insetBounds != null ? insetBounds : bounds);
+
+ // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen area,
+ // i.e. the screen area without the system bars.
final Configuration serviceConfig = mService.mConfiguration;
final Configuration config = new Configuration(Configuration.EMPTY);
// TODO(multidisplay): Update Dp to that of display stack is on.
final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
config.screenWidthDp =
- Math.min((int)(bounds.width() / density), serviceConfig.screenWidthDp);
+ Math.min((int)(mTmpStableBounds.width() / density), serviceConfig.screenWidthDp);
config.screenHeightDp =
- Math.min((int)(bounds.height() / density), serviceConfig.screenHeightDp);
- config.smallestScreenWidthDp =
- Math.min(config.screenWidthDp, config.screenHeightDp);
+ Math.min((int)(mTmpStableBounds.height() / density), serviceConfig.screenHeightDp);
+ config.smallestScreenWidthDp = Math.min(config.screenWidthDp, config.screenHeightDp);
+
+ // TODO: Orientation?
config.orientation = (config.screenWidthDp <= config.screenHeightDp)
? Configuration.ORIENTATION_PORTRAIT
: Configuration.ORIENTATION_LANDSCAPE;
+
+ // For calculating screen layout, we need to use the non-decor inset screen area for the
+ // calculation for compatibility reasons, i.e. screen area without system bars that could
+ // never go away in Honeycomb.
+ final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density);
+ final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density);
final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
- int longSize = Math.max(config.screenWidthDp, config.screenHeightDp);
- int shortSize = Math.min(config.screenWidthDp, config.screenHeightDp);
+ final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
+ final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
return config;
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index cefaa8d..05aabf1 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1500,6 +1500,9 @@
if (authority.ident > highestAuthorityId) {
highestAuthorityId = authority.ident;
}
+ } else {
+ EventLog.writeEvent(0x534e4554, "26513719", -1,
+ "Malformed authority");
}
} else if (XML_TAG_LISTEN_FOR_TICKLES.equals(tagName)) {
parseListenForTickles(parser);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 1908f72..5c80d04 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -60,22 +60,8 @@
// non-zero, which in turn ensures that the total weight is non-zero.
private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
- // If true, enables the use of the current time as an auto-brightness adjustment.
- // The basic idea here is to expand the dynamic range of auto-brightness
- // when it is especially dark outside. The light sensor tends to perform
- // poorly at low light levels so we compensate for it by making an
- // assumption about the environment.
- private static final boolean USE_TWILIGHT_ADJUSTMENT =
- PowerManager.useTwilightAdjustmentFeature();
-
// Specifies the maximum magnitude of the time of day adjustment.
- private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
-
- // The amount of time after or before sunrise over which to start adjusting
- // the gamma. We want the change to happen gradually so that it is below the
- // threshold of perceptibility and so that the adjustment has maximum effect
- // well after dusk.
- private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
+ private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1f;
// Debounce for sampling user-initiated changes in display brightness to ensure
// the user is satisfied with the result before storing the sample.
@@ -193,6 +179,8 @@
private int mBrightnessAdjustmentSampleOldBrightness;
private float mBrightnessAdjustmentSampleOldGamma;
+ private boolean mUseTwilight;
+
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
int brightnessMin, int brightnessMax, float dozeScaleFactor,
@@ -221,10 +209,6 @@
if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
-
- if (USE_TWILIGHT_ADJUSTMENT) {
- mTwilight.registerListener(mTwilightListener, mHandler);
- }
}
public int getAutomaticScreenBrightness() {
@@ -235,7 +219,7 @@
}
public void configure(boolean enable, float adjustment, boolean dozing,
- boolean userInitiatedChange) {
+ boolean userInitiatedChange, boolean useTwilight) {
// While dozing, the application processor may be suspended which will prevent us from
// receiving new information from the light sensor. On some devices, we may be able to
// switch to a wake-up light sensor instead but for now we will simply disable the sensor
@@ -244,6 +228,7 @@
mDozing = dozing;
boolean changed = setLightSensorEnabled(enable && !dozing);
changed |= setScreenAutoBrightnessAdjustment(adjustment);
+ changed |= setUseTwilight(useTwilight);
if (changed) {
updateAutoBrightness(false /*sendUpdate*/);
}
@@ -252,6 +237,17 @@
}
}
+ private boolean setUseTwilight(boolean useTwilight) {
+ if (mUseTwilight == useTwilight) return false;
+ if (useTwilight) {
+ mTwilight.registerListener(mTwilightListener, mHandler);
+ } else {
+ mTwilight.unregisterListener(mTwilightListener);
+ }
+ mUseTwilight = useTwilight;
+ return true;
+ }
+
public void dump(PrintWriter pw) {
pw.println();
pw.println("Automatic Brightness Controller Configuration:");
@@ -484,18 +480,13 @@
}
}
- if (USE_TWILIGHT_ADJUSTMENT) {
+ if (mUseTwilight) {
TwilightState state = mTwilight.getCurrentState();
if (state != null && state.isNight()) {
final long now = System.currentTimeMillis();
- final float earlyGamma =
- getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
- final float lateGamma =
- getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
- gamma *= earlyGamma * lateGamma;
+ gamma *= 1 + state.getAmount() * TWILIGHT_ADJUSTMENT_MAX_GAMMA;
if (DEBUG) {
- Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
- + ", lateGamma=" + lateGamma);
+ Slog.d(TAG, "updateAutoBrightness: twilight amount=" + state.getAmount());
}
}
}
@@ -579,25 +570,6 @@
}
}
- private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
- if (lastSunset < 0 || nextSunrise < 0
- || now < lastSunset || now > nextSunrise) {
- return 1.0f;
- }
-
- if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
- return MathUtils.lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
- (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
- }
-
- if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
- return MathUtils.lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
- (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
- }
-
- return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
- }
-
private final class AutomaticBrightnessHandler extends Handler {
public AutomaticBrightnessHandler(Looper looper) {
super(looper, null, true /*async*/);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 1038d97..1ed7070 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -615,7 +615,7 @@
&& mPowerRequest.brightnessSetByUser;
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mPowerRequest.screenAutoBrightnessAdjustment, state != Display.STATE_ON,
- userInitiatedChange);
+ userInitiatedChange, mPowerRequest.useTwilight);
}
// Apply brightness boost.
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 57cede8..811c947 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -78,13 +78,15 @@
* Any function with the suffix 'Locked' also needs to lock on {@link #mJobs}.
* @hide
*/
-public class JobSchedulerService extends com.android.server.SystemService
+public final class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {
public static final boolean DEBUG = false;
/** The number of concurrent jobs we run at one time. */
private static final int MAX_JOB_CONTEXTS_COUNT
= ActivityManager.isLowRamDeviceStatic() ? 3 : 6;
static final String TAG = "JobSchedulerService";
+ /** Global local for all job scheduler state. */
+ final Object mLock = new Object();
/** Master list of jobs. */
final JobStore mJobs;
@@ -207,6 +209,10 @@
}
};
+ public Object getLock() {
+ return mLock;
+ }
+
@Override
public void onStartUser(int userHandle) {
mStartedUsers.add(userHandle);
@@ -231,7 +237,7 @@
}
public int scheduleAsPackage(JobInfo job, int uId, String packageName, int userId) {
- JobStatus jobStatus = new JobStatus(job, uId, packageName, userId);
+ JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId);
try {
if (ActivityManagerNative.getDefault().getAppStartMode(uId,
job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
@@ -243,7 +249,7 @@
}
if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
JobStatus toCancel;
- synchronized (mJobs) {
+ synchronized (mLock) {
toCancel = mJobs.getJobByUidAndJobId(uId, job.getId());
}
startTrackingJob(jobStatus, toCancel);
@@ -256,7 +262,7 @@
public List<JobInfo> getPendingJobs(int uid) {
ArrayList<JobInfo> outList = new ArrayList<JobInfo>();
- synchronized (mJobs) {
+ synchronized (mLock) {
ArraySet<JobStatus> jobs = mJobs.getJobs();
for (int i=0; i<jobs.size(); i++) {
JobStatus job = jobs.valueAt(i);
@@ -270,7 +276,7 @@
void cancelJobsForUser(int userHandle) {
List<JobStatus> jobsForUser;
- synchronized (mJobs) {
+ synchronized (mLock) {
jobsForUser = mJobs.getJobsByUser(userHandle);
}
for (int i=0; i<jobsForUser.size(); i++) {
@@ -289,7 +295,7 @@
*/
public void cancelJobsForUid(int uid, boolean forceAll) {
List<JobStatus> jobsForUid;
- synchronized (mJobs) {
+ synchronized (mLock) {
jobsForUid = mJobs.getJobsByUid(uid);
}
for (int i=0; i<jobsForUid.size(); i++) {
@@ -317,7 +323,7 @@
*/
public void cancelJob(int uid, int jobId) {
JobStatus toCancel;
- synchronized (mJobs) {
+ synchronized (mLock) {
toCancel = mJobs.getJobByUidAndJobId(uid, jobId);
}
if (toCancel != null) {
@@ -328,7 +334,7 @@
private void cancelJobImpl(JobStatus cancelled) {
if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
stopTrackingJob(cancelled, true /* writeBack */);
- synchronized (mJobs) {
+ synchronized (mLock) {
// Remove from pending queue.
mPendingJobs.remove(cancelled);
// Cancel if running.
@@ -340,7 +346,7 @@
void updateIdleMode(boolean enabled) {
boolean changed = false;
boolean rocking;
- synchronized (mJobs) {
+ synchronized (mLock) {
if (mDeviceIdleMode != enabled) {
changed = true;
}
@@ -352,7 +358,7 @@
mControllers.get(i).deviceIdleModeChanged(enabled);
}
}
- synchronized (mJobs) {
+ synchronized (mLock) {
mDeviceIdleMode = enabled;
if (enabled) {
// When becoming idle, make sure no jobs are actively running.
@@ -451,7 +457,7 @@
// ignored; both services live in system_server
}
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- synchronized (mJobs) {
+ synchronized (mLock) {
// Let's go!
mReadyToRock = true;
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
@@ -470,7 +476,7 @@
JobStatus job = jobs.valueAt(i);
for (int controller=0; controller<mControllers.size(); controller++) {
mControllers.get(controller).deviceIdleModeChanged(mDeviceIdleMode);
- mControllers.get(controller).maybeStartTrackingJob(job, null);
+ mControllers.get(controller).maybeStartTrackingJobLocked(job, null);
}
}
// GO GO GO!
@@ -485,19 +491,16 @@
* about.
*/
private void startTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
- boolean update;
- boolean rocking;
- synchronized (mJobs) {
- update = mJobs.add(jobStatus);
- rocking = mReadyToRock;
- }
- if (rocking) {
- for (int i=0; i<mControllers.size(); i++) {
- StateController controller = mControllers.get(i);
- if (update) {
- controller.maybeStopTrackingJob(jobStatus, true);
+ synchronized (mLock) {
+ final boolean update = mJobs.add(jobStatus);
+ if (mReadyToRock) {
+ for (int i = 0; i < mControllers.size(); i++) {
+ StateController controller = mControllers.get(i);
+ if (update) {
+ controller.maybeStopTrackingJobLocked(jobStatus, true);
+ }
+ controller.maybeStartTrackingJobLocked(jobStatus, lastJob);
}
- controller.maybeStartTrackingJob(jobStatus, lastJob);
}
}
}
@@ -507,20 +510,17 @@
* object removed.
*/
private boolean stopTrackingJob(JobStatus jobStatus, boolean writeBack) {
- boolean removed;
- boolean rocking;
- synchronized (mJobs) {
+ synchronized (mLock) {
// Remove from store as well as controllers.
- removed = mJobs.remove(jobStatus, writeBack);
- rocking = mReadyToRock;
- }
- if (removed && rocking) {
- for (int i=0; i<mControllers.size(); i++) {
- StateController controller = mControllers.get(i);
- controller.maybeStopTrackingJob(jobStatus, false);
+ final boolean removed = mJobs.remove(jobStatus, writeBack);
+ if (removed && mReadyToRock) {
+ for (int i=0; i<mControllers.size(); i++) {
+ StateController controller = mControllers.get(i);
+ controller.maybeStopTrackingJobLocked(jobStatus, false);
+ }
}
+ return removed;
}
- return removed;
}
private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
@@ -693,14 +693,14 @@
@Override
public void handleMessage(Message message) {
- synchronized (mJobs) {
+ synchronized (mLock) {
if (!mReadyToRock) {
return;
}
}
switch (message.what) {
case MSG_JOB_EXPIRED:
- synchronized (mJobs) {
+ synchronized (mLock) {
JobStatus runNow = (JobStatus) message.obj;
// runNow can be null, which is a controller's way of indicating that its
// state is such that all ready jobs should be run immediately.
@@ -712,7 +712,7 @@
}
break;
case MSG_CHECK_JOB:
- synchronized (mJobs) {
+ synchronized (mLock) {
if (mReportedActive) {
// if jobs are currently being run, queue all ready jobs for execution.
queueReadyJobsForExecutionLockedH();
@@ -723,7 +723,7 @@
}
break;
case MSG_CHECK_JOB_GREEDY:
- synchronized (mJobs) {
+ synchronized (mLock) {
queueReadyJobsForExecutionLockedH();
}
break;
@@ -753,7 +753,7 @@
Slog.d(TAG, " queued " + job.toShortString());
}
mPendingJobs.add(job);
- } else if (areJobConstraintsNotSatisfied(job)) {
+ } else if (areJobConstraintsNotSatisfiedLocked(job)) {
stopJobOnServiceContextLocked(job,
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
}
@@ -820,7 +820,7 @@
runnableJobs = new ArrayList<>();
}
runnableJobs.add(job);
- } else if (areJobConstraintsNotSatisfied(job)) {
+ } else if (areJobConstraintsNotSatisfiedLocked(job)) {
stopJobOnServiceContextLocked(job,
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
}
@@ -869,7 +869,7 @@
* - It's not ready
* - It's running on a JSC.
*/
- private boolean areJobConstraintsNotSatisfied(JobStatus job) {
+ private boolean areJobConstraintsNotSatisfiedLocked(JobStatus job) {
return !job.isReady() && isCurrentlyActiveLocked(job);
}
@@ -879,7 +879,7 @@
* here is where we decide whether to actually execute it.
*/
private void maybeRunPendingJobsH() {
- synchronized (mJobs) {
+ synchronized (mLock) {
if (mDeviceIdleMode) {
// If device is idle, we will not schedule jobs to run.
return;
@@ -887,7 +887,7 @@
if (DEBUG) {
Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
}
- assignJobsToContextsH();
+ assignJobsToContextsLocked();
reportActive();
}
}
@@ -899,7 +899,7 @@
* run higher priority ones.
* Lock on mJobs before calling this function.
*/
- private void assignJobsToContextsH() {
+ private void assignJobsToContextsLocked() {
if (DEBUG) {
Slog.d(TAG, printPendingQueue());
}
@@ -984,7 +984,7 @@
}
for (int ic=0; ic<mControllers.size(); ic++) {
StateController controller = mControllers.get(ic);
- controller.prepareForExecution(contextIdToJobMap[i]);
+ controller.prepareForExecutionLocked(contextIdToJobMap[i]);
}
if (!mActiveServices.get(i).executeRunnableJob(contextIdToJobMap[i])) {
Slog.d(TAG, "Error executing " + contextIdToJobMap[i]);
@@ -1185,7 +1185,7 @@
void dumpInternal(PrintWriter pw) {
final long now = SystemClock.elapsedRealtime();
- synchronized (mJobs) {
+ synchronized (mLock) {
pw.print("Started users: ");
for (int i=0; i<mStartedUsers.size(); i++) {
pw.print("u" + mStartedUsers.get(i) + " ");
@@ -1216,7 +1216,7 @@
}
for (int i=0; i<mControllers.size(); i++) {
pw.println();
- mControllers.get(i).dumpControllerState(pw);
+ mControllers.get(i).dumpControllerStateLocked(pw);
}
pw.println();
pw.println(printPendingQueue());
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index b249739..48549ce 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -103,6 +103,7 @@
private final JobCompletedListener mCompletedListener;
/** Used for service binding, etc. */
private final Context mContext;
+ private final Object mLock;
private final IBatteryStats mBatteryStats;
private PowerManager.WakeLock mWakeLock;
@@ -124,7 +125,6 @@
private int mPreferredUid;
IJobService service;
- private final Object mLock = new Object();
/**
* Whether this context is free. This is set to false at the start of execution, and reset to
* true when execution is complete.
@@ -137,13 +137,14 @@
private long mTimeoutElapsed;
JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, Looper looper) {
- this(service.getContext(), batteryStats, service, looper);
+ this(service.getContext(), service.getLock(), batteryStats, service, looper);
}
@VisibleForTesting
- JobServiceContext(Context context, IBatteryStats batteryStats,
+ JobServiceContext(Context context, Object lock, IBatteryStats batteryStats,
JobCompletedListener completedListener, Looper looper) {
mContext = context;
+ mLock = lock;
mBatteryStats = batteryStats;
mCallbackHandler = new JobServiceHandler(looper);
mCompletedListener = completedListener;
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 3565fc1..6020247 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -44,7 +44,6 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -70,6 +69,7 @@
/** Threshold to adjust how often we want to write to the db. */
private static final int MAX_OPS_BEFORE_WRITE = 1;
final ArraySet<JobStatus> mJobSet;
+ final Object mLock;
final Context mContext;
private int mDirtyOperations;
@@ -85,7 +85,7 @@
synchronized (sSingletonLock) {
if (sSingleton == null) {
sSingleton = new JobStore(jobManagerService.getContext(),
- Environment.getDataDirectory());
+ jobManagerService.getLock(), Environment.getDataDirectory());
}
return sSingleton;
}
@@ -96,7 +96,7 @@
*/
@VisibleForTesting
public static JobStore initAndGetForTesting(Context context, File dataDir) {
- JobStore jobStoreUnderTest = new JobStore(context, dataDir);
+ JobStore jobStoreUnderTest = new JobStore(context, new Object(), dataDir);
jobStoreUnderTest.clear();
return jobStoreUnderTest;
}
@@ -104,7 +104,8 @@
/**
* Construct the instance of the job store. This results in a blocking read from disk.
*/
- private JobStore(Context context, File dataDir) {
+ private JobStore(Context context, Object lock, File dataDir) {
+ mLock = lock;
mContext = context;
mDirtyOperations = 0;
@@ -266,14 +267,14 @@
/**
* Runnable that writes {@link #mJobSet} out to xml.
- * NOTE: This Runnable locks on JobStore.this
+ * NOTE: This Runnable locks on mLock
*/
private class WriteJobsMapToDiskRunnable implements Runnable {
@Override
public void run() {
final long startElapsed = SystemClock.elapsedRealtime();
List<JobStatus> mStoreCopy = new ArrayList<JobStatus>();
- synchronized (JobStore.this) {
+ synchronized (mLock) {
// Copy over the jobs so we can release the lock before writing.
for (int i=0; i<mJobSet.size(); i++) {
JobStatus jobStatus = mJobSet.valueAt(i);
@@ -454,7 +455,7 @@
try {
List<JobStatus> jobs;
FileInputStream fis = mJobsFile.openRead();
- synchronized (JobStore.this) {
+ synchronized (mLock) {
jobs = readJobMapImpl(fis);
if (jobs != null) {
for (int i=0; i<jobs.size(); i++) {
@@ -678,8 +679,8 @@
parser.nextTag(); // Consume </extras>
JobStatus js = new JobStatus(
- jobBuilder.build(), uid, sourcePackageName, sourceUserId, elapsedRuntimes.first,
- elapsedRuntimes.second);
+ jobBuilder.build(), uid, sourcePackageName, sourceUserId,
+ elapsedRuntimes.first, elapsedRuntimes.second);
return js;
}
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 5f3da75..f0c579f 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -48,59 +48,56 @@
public static AppIdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
- sController = new AppIdleController(service, service.getContext());
+ sController = new AppIdleController(service, service.getContext(),
+ service.getLock());
}
return sController;
}
}
- private AppIdleController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private AppIdleController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
}
@Override
- public void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.add(jobStatus);
- String packageName = jobStatus.getSourcePackageName();
- final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
- jobStatus.getSourceUid(), jobStatus.getSourceUserId());
- if (DEBUG) {
- Slog.d(LOG_TAG, "Start tracking, setting idle state of "
- + packageName + " to " + appIdle);
- }
- jobStatus.appNotIdleConstraintSatisfied.set(!appIdle);
+ public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
+ mTrackedTasks.add(jobStatus);
+ String packageName = jobStatus.getSourcePackageName();
+ final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
+ jobStatus.getSourceUid(), jobStatus.getSourceUserId());
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Start tracking, setting idle state of "
+ + packageName + " to " + appIdle);
}
+ jobStatus.setAppNotIdleConstraintSatisfied(!appIdle);
}
@Override
- public void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.remove(jobStatus);
- }
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate) {
+ mTrackedTasks.remove(jobStatus);
}
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("AppIdle");
pw.println("Parole On: " + mAppIdleParoleOn);
- synchronized (mTrackedTasks) {
- for (JobStatus task : mTrackedTasks) {
- pw.print(task.getSourcePackageName());
- pw.print(":idle=" + !task.appNotIdleConstraintSatisfied.get());
- pw.print(", ");
- }
- pw.println();
+ for (JobStatus task : mTrackedTasks) {
+ pw.print(task.getSourcePackageName());
+ pw.print(":idle="
+ + ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
+ pw.print(", ");
}
+ pw.println();
}
void setAppIdleParoleOn(boolean isAppIdleParoleOn) {
// Flag if any app's idle state has changed
boolean changed = false;
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
if (mAppIdleParoleOn == isAppIdleParoleOn) {
return;
}
@@ -112,8 +109,7 @@
if (DEBUG) {
Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
}
- if (task.appNotIdleConstraintSatisfied.get() == appIdle) {
- task.appNotIdleConstraintSatisfied.set(!appIdle);
+ if (task.setAppNotIdleConstraintSatisfied(!appIdle)) {
changed = true;
}
}
@@ -128,19 +124,18 @@
@Override
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
boolean changed = false;
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
if (mAppIdleParoleOn) {
return;
}
for (JobStatus task : mTrackedTasks) {
if (task.getSourcePackageName().equals(packageName)
&& task.getSourceUserId() == userId) {
- if (task.appNotIdleConstraintSatisfied.get() != !idle) {
+ if (task.setAppNotIdleConstraintSatisfied(!idle)) {
if (DEBUG) {
Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
+ packageName + " to " + idle);
}
- task.appNotIdleConstraintSatisfied.set(!idle);
changed = true;
}
}
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index b322a3e..ac9f425 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -53,7 +53,7 @@
synchronized (sCreationLock) {
if (sController == null) {
sController = new BatteryController(taskManagerService,
- taskManagerService.getContext());
+ taskManagerService.getContext(), taskManagerService.getLock());
}
}
return sController;
@@ -67,32 +67,29 @@
@VisibleForTesting
public static BatteryController getForTesting(StateChangedListener stateChangedListener,
Context context) {
- return new BatteryController(stateChangedListener, context);
+ return new BatteryController(stateChangedListener, context, new Object());
}
- private BatteryController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private BatteryController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
mChargeTracker = new ChargingTracker();
mChargeTracker.startTracking();
}
@Override
- public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
final boolean isOnStablePower = mChargeTracker.isOnStablePower();
if (taskStatus.hasChargingConstraint()) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.add(taskStatus);
- taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
- }
+ mTrackedTasks.add(taskStatus);
+ taskStatus.setChargingConstraintSatisfied(isOnStablePower);
}
}
@Override
- public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, boolean forUpdate) {
if (taskStatus.hasChargingConstraint()) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.remove(taskStatus);
- }
+ mTrackedTasks.remove(taskStatus);
}
}
@@ -102,9 +99,9 @@
Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
}
boolean reportChange = false;
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
for (JobStatus ts : mTrackedTasks) {
- boolean previous = ts.chargingConstraintSatisfied.getAndSet(stablePower);
+ boolean previous = ts.setChargingConstraintSatisfied(stablePower);
if (previous != stablePower) {
reportChange = true;
}
@@ -197,18 +194,16 @@
}
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("Batt.");
pw.println("Stable power: " + mChargeTracker.isOnStablePower());
- synchronized (mTrackedTasks) {
- Iterator<JobStatus> it = mTrackedTasks.iterator();
- if (it.hasNext()) {
- pw.print(String.valueOf(it.next().hashCode()));
- }
- while (it.hasNext()) {
- pw.print("," + String.valueOf(it.next().hashCode()));
- }
- pw.println();
+ Iterator<JobStatus> it = mTrackedTasks.iterator();
+ if (it.hasNext()) {
+ pw.print(String.valueOf(it.next().hashCode()));
}
+ while (it.hasNext()) {
+ pw.print("," + String.valueOf(it.next().hashCode()));
+ }
+ pw.println();
}
}
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index b84658a..bd06645 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -58,14 +58,15 @@
public static ConnectivityController get(JobSchedulerService jms) {
synchronized (sCreationLock) {
if (mSingleton == null) {
- mSingleton = new ConnectivityController(jms, jms.getContext());
+ mSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock());
}
return mSingleton;
}
}
- private ConnectivityController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private ConnectivityController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
// Register connectivity changed BR.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
@@ -82,22 +83,18 @@
}
@Override
- public void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
- synchronized (mTrackedJobs) {
- jobStatus.connectivityConstraintSatisfied.set(mNetworkConnected);
- jobStatus.unmeteredConstraintSatisfied.set(mNetworkUnmetered);
- mTrackedJobs.add(jobStatus);
- }
+ jobStatus.setConnectivityConstraintSatisfied(mNetworkConnected);
+ jobStatus.setUnmeteredConstraintSatisfied(mNetworkUnmetered);
+ mTrackedJobs.add(jobStatus);
}
}
@Override
- public void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate) {
if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
- synchronized (mTrackedJobs) {
- mTrackedJobs.remove(jobStatus);
- }
+ mTrackedJobs.remove(jobStatus);
}
}
@@ -105,18 +102,14 @@
* @param userId Id of the user for whom we are updating the connectivity state.
*/
private void updateTrackedJobs(int userId) {
- synchronized (mTrackedJobs) {
+ synchronized (mLock) {
boolean changed = false;
for (JobStatus js : mTrackedJobs) {
if (js.getUserId() != userId) {
continue;
}
- boolean prevIsConnected =
- js.connectivityConstraintSatisfied.getAndSet(mNetworkConnected);
- boolean prevIsMetered = js.unmeteredConstraintSatisfied.getAndSet(mNetworkUnmetered);
- if (prevIsConnected != mNetworkConnected || prevIsMetered != mNetworkUnmetered) {
- changed = true;
- }
+ changed |= js.setConnectivityConstraintSatisfied(mNetworkConnected);
+ changed |= js.setUnmeteredConstraintSatisfied(mNetworkUnmetered);
}
if (changed) {
mStateChangedListener.onControllerStateChanged();
@@ -128,7 +121,7 @@
* We know the network has just come up. We want to run any jobs that are ready.
*/
public synchronized void onNetworkActive() {
- synchronized (mTrackedJobs) {
+ synchronized (mLock) {
for (JobStatus js : mTrackedJobs) {
if (js.isReady()) {
if (DEBUG) {
@@ -188,7 +181,7 @@
};
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("Conn.");
pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
for (JobStatus js: mTrackedJobs) {
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index 212cc94..c5cf30f 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -57,7 +57,7 @@
synchronized (sCreationLock) {
if (sController == null) {
sController = new ContentObserverController(taskManagerService,
- taskManagerService.getContext());
+ taskManagerService.getContext(), taskManagerService.getLock());
}
}
return sController;
@@ -66,95 +66,90 @@
@VisibleForTesting
public static ContentObserverController getForTesting(StateChangedListener stateChangedListener,
Context context) {
- return new ContentObserverController(stateChangedListener, context);
+ return new ContentObserverController(stateChangedListener, context, new Object());
}
- private ContentObserverController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private ContentObserverController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
}
@Override
- public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasContentTriggerConstraint()) {
- synchronized (mTrackedTasks) {
- if (taskStatus.contentObserverJobInstance == null) {
- taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
- }
- mTrackedTasks.add(taskStatus);
- boolean havePendingUris = false;
- // If there is a previous job associated with the new job, propagate over
- // any pending content URI trigger reports.
- if (lastJob != null && lastJob.contentObserverJobInstance != null
- && lastJob.contentObserverJobInstance
- != taskStatus.contentObserverJobInstance
- && lastJob.contentObserverJobInstance.mChangedAuthorities != null) {
- havePendingUris = true;
+ if (taskStatus.contentObserverJobInstance == null) {
+ taskStatus.contentObserverJobInstance = new JobInstance(taskStatus);
+ }
+ mTrackedTasks.add(taskStatus);
+ boolean havePendingUris = false;
+ // If there is a previous job associated with the new job, propagate over
+ // any pending content URI trigger reports.
+ if (lastJob != null && lastJob.contentObserverJobInstance != null
+ && lastJob.contentObserverJobInstance
+ != taskStatus.contentObserverJobInstance
+ && lastJob.contentObserverJobInstance.mChangedAuthorities != null) {
+ havePendingUris = true;
+ taskStatus.contentObserverJobInstance.mChangedAuthorities
+ = lastJob.contentObserverJobInstance.mChangedAuthorities;
+ taskStatus.contentObserverJobInstance.mChangedUris
+ = lastJob.contentObserverJobInstance.mChangedUris;
+ lastJob.contentObserverJobInstance.mChangedAuthorities = null;
+ lastJob.contentObserverJobInstance.mChangedUris = null;
+ }
+ // If we have previously reported changed authorities/uris, then we failed
+ // to complete the job with them so will re-record them to report again.
+ if (taskStatus.changedAuthorities != null) {
+ havePendingUris = true;
+ if (taskStatus.contentObserverJobInstance.mChangedAuthorities == null) {
taskStatus.contentObserverJobInstance.mChangedAuthorities
- = lastJob.contentObserverJobInstance.mChangedAuthorities;
- taskStatus.contentObserverJobInstance.mChangedUris
- = lastJob.contentObserverJobInstance.mChangedUris;
- lastJob.contentObserverJobInstance.mChangedAuthorities = null;
- lastJob.contentObserverJobInstance.mChangedUris = null;
+ = new ArraySet<>();
}
- // If we have previously reported changed authorities/uris, then we failed
- // to complete the job with them so will re-record them to report again.
- if (taskStatus.changedAuthorities != null) {
- havePendingUris = true;
- if (taskStatus.contentObserverJobInstance.mChangedAuthorities == null) {
- taskStatus.contentObserverJobInstance.mChangedAuthorities
- = new ArraySet<>();
+ for (String auth : taskStatus.changedAuthorities) {
+ taskStatus.contentObserverJobInstance.mChangedAuthorities.add(auth);
+ }
+ if (taskStatus.changedUris != null) {
+ if (taskStatus.contentObserverJobInstance.mChangedUris == null) {
+ taskStatus.contentObserverJobInstance.mChangedUris = new ArraySet<>();
}
- for (String auth : taskStatus.changedAuthorities) {
- taskStatus.contentObserverJobInstance.mChangedAuthorities.add(auth);
+ for (Uri uri : taskStatus.changedUris) {
+ taskStatus.contentObserverJobInstance.mChangedUris.add(uri);
}
- if (taskStatus.changedUris != null) {
- if (taskStatus.contentObserverJobInstance.mChangedUris == null) {
- taskStatus.contentObserverJobInstance.mChangedUris = new ArraySet<>();
- }
- for (Uri uri : taskStatus.changedUris) {
- taskStatus.contentObserverJobInstance.mChangedUris.add(uri);
- }
- }
- taskStatus.changedAuthorities = null;
- taskStatus.changedUris = null;
}
taskStatus.changedAuthorities = null;
taskStatus.changedUris = null;
- taskStatus.contentTriggerConstraintSatisfied.set(havePendingUris);
+ }
+ taskStatus.changedAuthorities = null;
+ taskStatus.changedUris = null;
+ taskStatus.setContentTriggerConstraintSatisfied(havePendingUris);
+ }
+ }
+
+ @Override
+ public void prepareForExecutionLocked(JobStatus taskStatus) {
+ if (taskStatus.hasContentTriggerConstraint()) {
+ if (taskStatus.contentObserverJobInstance != null) {
+ taskStatus.changedUris = taskStatus.contentObserverJobInstance.mChangedUris;
+ taskStatus.changedAuthorities
+ = taskStatus.contentObserverJobInstance.mChangedAuthorities;
+ taskStatus.contentObserverJobInstance.mChangedUris = null;
+ taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
}
}
}
@Override
- public void prepareForExecution(JobStatus taskStatus) {
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, boolean forUpdate) {
if (taskStatus.hasContentTriggerConstraint()) {
- synchronized (mTrackedTasks) {
+ if (!forUpdate) {
+ // We won't do this reset if being called for an update, because
+ // we know it will be immediately followed by maybeStartTrackingJobLocked...
+ // and we don't want to lose any content changes in-between.
if (taskStatus.contentObserverJobInstance != null) {
- taskStatus.changedUris = taskStatus.contentObserverJobInstance.mChangedUris;
- taskStatus.changedAuthorities
- = taskStatus.contentObserverJobInstance.mChangedAuthorities;
- taskStatus.contentObserverJobInstance.mChangedUris = null;
- taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
+ taskStatus.contentObserverJobInstance.detach();
+ taskStatus.contentObserverJobInstance = null;
}
}
- }
- }
-
- @Override
- public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
- if (taskStatus.hasContentTriggerConstraint()) {
- synchronized (mTrackedTasks) {
- if (!forUpdate) {
- // We won't do this reset if being called for an update, because
- // we know it will be immediately followed by maybeStartTrackingJob...
- // and we don't want to lose any content changes in-between.
- if (taskStatus.contentObserverJobInstance != null) {
- taskStatus.contentObserverJobInstance.detach();
- taskStatus.contentObserverJobInstance = null;
- }
- }
- mTrackedTasks.remove(taskStatus);
- }
+ mTrackedTasks.remove(taskStatus);
}
}
@@ -162,7 +157,7 @@
public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) {
if (failureToReschedule.hasContentTriggerConstraint()
&& newJob.hasContentTriggerConstraint()) {
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
// Our job has failed, and we are scheduling a new job for it.
// Copy the last reported content changes in to the new job, so when
// we schedule the new one we will pick them up and report them again.
@@ -184,7 +179,7 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
boolean reportChange = false;
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
final int N = mJobs.size();
for (int i=0; i<N; i++) {
JobInstance inst = mJobs.get(i);
@@ -198,9 +193,7 @@
inst.mChangedAuthorities = new ArraySet<>();
}
inst.mChangedAuthorities.add(uri.getAuthority());
- boolean previous
- = inst.mJobStatus.contentTriggerConstraintSatisfied.getAndSet(true);
- if (!previous) {
+ if (inst.mJobStatus.setContentTriggerConstraintSatisfied(true)) {
reportChange = true;
}
}
@@ -254,50 +247,48 @@
}
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("Content.");
- synchronized (mTrackedTasks) {
- Iterator<JobStatus> it = mTrackedTasks.iterator();
- if (it.hasNext()) {
- pw.print(String.valueOf(it.next().hashCode()));
- }
- while (it.hasNext()) {
- pw.print("," + String.valueOf(it.next().hashCode()));
- }
- pw.println();
- int N = mObservers.size();
- if (N > 0) {
- pw.println("URIs:");
- for (int i = 0; i < N; i++) {
- ObserverInstance obs = mObservers.valueAt(i);
- pw.print(" ");
- pw.print(mObservers.keyAt(i));
- pw.println(":");
- pw.print(" ");
- pw.println(obs);
- pw.println(" Jobs:");
- int M = obs.mJobs.size();
- for (int j=0; j<M; j++) {
- JobInstance inst = obs.mJobs.get(j);
- pw.print(" ");
- pw.print(inst.hashCode());
- if (inst.mChangedAuthorities != null) {
- pw.println(":");
- pw.println(" Changed Authorities:");
- for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
- pw.print(" ");
- pw.println(inst.mChangedAuthorities.valueAt(k));
- }
- if (inst.mChangedUris != null) {
- pw.println(" Changed URIs:");
- for (int k = 0; k<inst.mChangedUris.size(); k++) {
- pw.print(" ");
- pw.println(inst.mChangedUris.valueAt(k));
- }
- }
- } else {
- pw.println();
+ Iterator<JobStatus> it = mTrackedTasks.iterator();
+ if (it.hasNext()) {
+ pw.print(String.valueOf(it.next().hashCode()));
+ }
+ while (it.hasNext()) {
+ pw.print("," + String.valueOf(it.next().hashCode()));
+ }
+ pw.println();
+ int N = mObservers.size();
+ if (N > 0) {
+ pw.println("URIs:");
+ for (int i = 0; i < N; i++) {
+ ObserverInstance obs = mObservers.valueAt(i);
+ pw.print(" ");
+ pw.print(mObservers.keyAt(i));
+ pw.println(":");
+ pw.print(" ");
+ pw.println(obs);
+ pw.println(" Jobs:");
+ int M = obs.mJobs.size();
+ for (int j=0; j<M; j++) {
+ JobInstance inst = obs.mJobs.get(j);
+ pw.print(" ");
+ pw.print(inst.hashCode());
+ if (inst.mChangedAuthorities != null) {
+ pw.println(":");
+ pw.println(" Changed Authorities:");
+ for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
+ pw.print(" ");
+ pw.println(inst.mChangedAuthorities.valueAt(k));
}
+ if (inst.mChangedUris != null) {
+ pw.println(" Changed URIs:");
+ for (int k = 0; k<inst.mChangedUris.size(); k++) {
+ pw.print(" ");
+ pw.println(inst.mChangedUris.valueAt(k));
+ }
+ }
+ } else {
+ pw.println();
}
}
}
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 9f4cdef..7638494 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -51,14 +51,15 @@
public static IdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
- sController = new IdleController(service, service.getContext());
+ sController = new IdleController(service, service.getContext(), service.getLock());
}
return sController;
}
}
- private IdleController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private IdleController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
initIdleStateTracking();
}
@@ -66,29 +67,25 @@
* StateController interface
*/
@Override
- public void maybeStartTrackingJob(JobStatus taskStatus, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
if (taskStatus.hasIdleConstraint()) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.add(taskStatus);
- taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
- }
+ mTrackedTasks.add(taskStatus);
+ taskStatus.setIdleConstraintSatisfied(mIdleTracker.isIdle());
}
}
@Override
- public void maybeStopTrackingJob(JobStatus taskStatus, boolean forUpdate) {
- synchronized (mTrackedTasks) {
- mTrackedTasks.remove(taskStatus);
- }
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, boolean forUpdate) {
+ mTrackedTasks.remove(taskStatus);
}
/**
* Interaction with the task manager service
*/
void reportNewIdleState(boolean isIdle) {
- synchronized (mTrackedTasks) {
+ synchronized (mLock) {
for (JobStatus task : mTrackedTasks) {
- task.idleConstraintSatisfied.set(isIdle);
+ task.setIdleConstraintSatisfied(isIdle);
}
}
mStateChangedListener.onControllerStateChanged();
@@ -193,17 +190,15 @@
}
@Override
- public void dumpControllerState(PrintWriter pw) {
- synchronized (mTrackedTasks) {
- pw.print("Idle: ");
- pw.println(mIdleTracker.isIdle() ? "true" : "false");
- pw.println(mTrackedTasks.size());
- for (int i = 0; i < mTrackedTasks.size(); i++) {
- final JobStatus js = mTrackedTasks.get(i);
- pw.print(" ");
- pw.print(String.valueOf(js.hashCode()).substring(0, 3));
- pw.println("..");
- }
+ public void dumpControllerStateLocked(PrintWriter pw) {
+ pw.print("Idle: ");
+ pw.println(mIdleTracker.isIdle() ? "true" : "false");
+ pw.println(mTrackedTasks.size());
+ for (int i = 0; i < mTrackedTasks.size(); i++) {
+ final JobStatus js = mTrackedTasks.get(i);
+ pw.print(" ");
+ pw.print(String.valueOf(js.hashCode()).substring(0, 3));
+ 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 c4d564c..f835069 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -42,10 +42,19 @@
* but we don't enforce that so this is safer.
* @hide
*/
-public class JobStatus {
+public final class JobStatus {
public static final long NO_LATEST_RUNTIME = Long.MAX_VALUE;
public static final long NO_EARLIEST_RUNTIME = 0L;
+ static final int CONSTRAINT_CHARGING = 1<<0;
+ static final int CONSTRAINT_TIMING_DELAY = 1<<1;
+ static final int CONSTRAINT_DEADLINE = 1<<2;
+ static final int CONSTRAINT_IDLE = 1<<3;
+ static final int CONSTRAINT_UNMETERED = 1<<4;
+ static final int CONSTRAINT_CONNECTIVITY = 1<<5;
+ static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
+ static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
+
final JobInfo job;
/** Uid of the package requesting this job. */
final int callingUid;
@@ -56,15 +65,23 @@
final int sourceUserId;
final int sourceUid;
+ /**
+ * Earliest point in the future at which this job will be eligible to run. A value of 0
+ * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
+ */
+ private final long earliestRunTimeElapsedMillis;
+ /**
+ * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
+ * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
+ */
+ private final long latestRunTimeElapsedMillis;
+
+ /** How many times this job has failed, used to compute back-off. */
+ private final int numFailures;
+
// Constraints.
- final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean timeDelayConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean deadlineConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean unmeteredConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean appNotIdleConstraintSatisfied = new AtomicBoolean();
- final AtomicBoolean contentTriggerConstraintSatisfied = new AtomicBoolean();
+ final int requiredConstraints;
+ int satisfiedConstraints = 0;
// These are filled in by controllers when preparing for execution.
public ArraySet<Uri> changedUris;
@@ -76,31 +93,18 @@
*/
ContentObserverController.JobInstance contentObserverJobInstance;
- /**
- * Earliest point in the future at which this job will be eligible to run. A value of 0
- * indicates there is no delay constraint. See {@link #hasTimingDelayConstraint()}.
- */
- private long earliestRunTimeElapsedMillis;
- /**
- * Latest point in the future at which this job must be run. A value of {@link Long#MAX_VALUE}
- * indicates there is no deadline constraint. See {@link #hasDeadlineConstraint()}.
- */
- private long latestRunTimeElapsedMillis;
- /** How many times this job has failed, used to compute back-off. */
- private final int numFailures;
-
/** Provide a handle to the service that this job will be run on. */
public int getServiceToken() {
return callingUid;
}
- private JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
- int numFailures) {
+ private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
+ int sourceUserId, int numFailures, long earliestRunTimeElapsedMillis,
+ long latestRunTimeElapsedMillis) {
this.job = job;
this.callingUid = callingUid;
this.name = job.getService().flattenToShortString();
this.tag = "*job*/" + this.name;
- this.numFailures = numFailures;
int tempSourceUid = -1;
if (sourceUserId != -1 && sourcePackageName != null) {
@@ -120,38 +124,42 @@
this.sourceUserId = sourceUserId;
this.sourcePackageName = sourcePackageName;
}
+
+ this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
+ this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
+ this.numFailures = numFailures;
+
+ int requiredConstraints = 0;
+ if (job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY) {
+ requiredConstraints |= CONSTRAINT_CONNECTIVITY;
+ }
+ if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) {
+ requiredConstraints |= CONSTRAINT_UNMETERED;
+ }
+ if (job.isRequireCharging()) {
+ requiredConstraints |= CONSTRAINT_CHARGING;
+ }
+ if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
+ requiredConstraints |= CONSTRAINT_TIMING_DELAY;
+ }
+ if (latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
+ requiredConstraints |= CONSTRAINT_DEADLINE;
+ }
+ if (job.isRequireDeviceIdle()) {
+ requiredConstraints |= CONSTRAINT_IDLE;
+ }
+ if (job.getTriggerContentUris() != null) {
+ requiredConstraints |= CONSTRAINT_CONTENT_TRIGGER;
+ }
+ this.requiredConstraints = requiredConstraints;
}
/** Copy constructor. */
public JobStatus(JobStatus jobStatus) {
- this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.getSourcePackageName(),
- jobStatus.getSourceUserId(), jobStatus.getNumFailures());
- this.earliestRunTimeElapsedMillis = jobStatus.getEarliestRunTime();
- this.latestRunTimeElapsedMillis = jobStatus.getLatestRunTimeElapsed();
- }
-
- /**
- * Create a newly scheduled job.
- * @param callingUid Uid of the package that scheduled this job.
- * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
- * the calling package is the source.
- * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
- * calling userId.
- */
- public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId) {
- this(job, callingUid, sourcePackageName, sourceUserId, 0);
-
- final long elapsedNow = SystemClock.elapsedRealtime();
-
- if (job.isPeriodic()) {
- latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
- earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
- } else {
- earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
- elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
- latestRunTimeElapsedMillis = job.hasLateConstraint() ?
- elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
- }
+ this(jobStatus.getJob(), jobStatus.getUid(),
+ jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
+ jobStatus.getNumFailures(), jobStatus.getEarliestRunTime(),
+ jobStatus.getLatestRunTimeElapsed());
}
/**
@@ -161,22 +169,43 @@
* wallclock runtime rather than resetting it on every boot.
* We consider a freshly loaded job to no longer be in back-off.
*/
- public JobStatus(JobInfo job, int callingUid, String sourcePackageName, int sourceUserId,
- long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
- this(job, callingUid, sourcePackageName, sourceUserId, 0);
-
- this.earliestRunTimeElapsedMillis = earliestRunTimeElapsedMillis;
- this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
+ public JobStatus(JobInfo job, int callingUid, String sourcePackageName,
+ int sourceUserId, long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis) {
+ this(job, callingUid, sourcePackageName, sourceUserId, 0, earliestRunTimeElapsedMillis,
+ latestRunTimeElapsedMillis);
}
/** Create a new job to be rescheduled with the provided parameters. */
public JobStatus(JobStatus rescheduling, long newEarliestRuntimeElapsedMillis,
long newLatestRuntimeElapsedMillis, int backoffAttempt) {
- this(rescheduling.job, rescheduling.getUid(), rescheduling.getSourcePackageName(),
- rescheduling.getSourceUserId(), backoffAttempt);
+ this(rescheduling.job, rescheduling.getUid(),
+ rescheduling.getSourcePackageName(),
+ rescheduling.getSourceUserId(), backoffAttempt, newEarliestRuntimeElapsedMillis,
+ newLatestRuntimeElapsedMillis);
+ }
- earliestRunTimeElapsedMillis = newEarliestRuntimeElapsedMillis;
- latestRunTimeElapsedMillis = newLatestRuntimeElapsedMillis;
+ /**
+ * Create a newly scheduled job.
+ * @param callingUid Uid of the package that scheduled this job.
+ * @param sourcePackageName Package name on whose behalf this job is scheduled. Null indicates
+ * the calling package is the source.
+ * @param sourceUserId User id for whom this job is scheduled. -1 indicates this is same as the
+ */
+ public static JobStatus createFromJobInfo(JobInfo job, int callingUid, String sourcePackageName,
+ int sourceUserId) {
+ final long elapsedNow = SystemClock.elapsedRealtime();
+ final long earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis;
+ if (job.isPeriodic()) {
+ latestRunTimeElapsedMillis = elapsedNow + job.getIntervalMillis();
+ earliestRunTimeElapsedMillis = latestRunTimeElapsedMillis - job.getFlexMillis();
+ } else {
+ earliestRunTimeElapsedMillis = job.hasEarlyConstraint() ?
+ elapsedNow + job.getMinLatencyMillis() : NO_EARLIEST_RUNTIME;
+ latestRunTimeElapsedMillis = job.hasLateConstraint() ?
+ elapsedNow + job.getMaxExecutionDelayMillis() : NO_LATEST_RUNTIME;
+ }
+ return new JobStatus(job, callingUid, sourcePackageName, sourceUserId, 0,
+ earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis);
}
public JobInfo getJob() {
@@ -232,31 +261,31 @@
}
public boolean hasConnectivityConstraint() {
- return job.getNetworkType() == JobInfo.NETWORK_TYPE_ANY;
+ return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
}
public boolean hasUnmeteredConstraint() {
- return job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED;
+ return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
}
public boolean hasChargingConstraint() {
- return job.isRequireCharging();
+ return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
}
public boolean hasTimingDelayConstraint() {
- return earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME;
+ return (requiredConstraints&CONSTRAINT_TIMING_DELAY) != 0;
}
public boolean hasDeadlineConstraint() {
- return latestRunTimeElapsedMillis != NO_LATEST_RUNTIME;
+ return (requiredConstraints&CONSTRAINT_DEADLINE) != 0;
}
public boolean hasIdleConstraint() {
- return job.isRequireDeviceIdle();
+ return (requiredConstraints&CONSTRAINT_IDLE) != 0;
}
public boolean hasContentTriggerConstraint() {
- return job.getTriggerContentUris() != null;
+ return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
}
public boolean isPersisted() {
@@ -271,31 +300,74 @@
return latestRunTimeElapsedMillis;
}
+ boolean setChargingConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CHARGING, state);
+ }
+
+ boolean setTimingDelayConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_TIMING_DELAY, state);
+ }
+
+ boolean setDeadlineConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_DEADLINE, state);
+ }
+
+ boolean setIdleConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_IDLE, state);
+ }
+
+ boolean setUnmeteredConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
+ }
+
+ boolean setConnectivityConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
+ }
+
+ boolean setAppNotIdleConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_APP_NOT_IDLE, state);
+ }
+
+ boolean setContentTriggerConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
+ }
+
+ boolean setConstraintSatisfied(int constraint, boolean state) {
+ boolean old = (satisfiedConstraints&constraint) != 0;
+ if (old == state) {
+ return false;
+ }
+ satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
+ return true;
+ }
+
/**
* @return Whether or not this job is ready to run, based on its requirements. This is true if
* the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
*/
- public synchronized boolean isReady() {
+ 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
// satisfied).
// AppNotIdle implicit constraint trumps all!
return (isConstraintsSatisfied()
- || (!job.isPeriodic()
- && hasDeadlineConstraint() && deadlineConstraintSatisfied.get()))
- && appNotIdleConstraintSatisfied.get();
+ || (!job.isPeriodic()
+ && hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0))
+ && (satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0;
}
+ static final int CONSTRAINTS_OF_INTEREST =
+ CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
+ CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
+ CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
+
/**
* @return Whether the constraints set on this job are satisfied.
*/
- public synchronized boolean isConstraintsSatisfied() {
- return (!hasChargingConstraint() || chargingConstraintSatisfied.get())
- && (!hasTimingDelayConstraint() || timeDelayConstraintSatisfied.get())
- && (!hasConnectivityConstraint() || connectivityConstraintSatisfied.get())
- && (!hasUnmeteredConstraint() || unmeteredConstraintSatisfied.get())
- && (!hasIdleConstraint() || idleConstraintSatisfied.get())
- && (!hasContentTriggerConstraint() || contentTriggerConstraintSatisfied.get());
+ public boolean isConstraintsSatisfied() {
+ final int req = requiredConstraints & CONSTRAINTS_OF_INTEREST;
+ final int sat = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
+ return (sat & req) == req;
}
public boolean matches(int uid, int jobId) {
@@ -314,7 +386,7 @@
+ ",I=" + job.isRequireDeviceIdle()
+ ",U=" + (job.getTriggerContentUris() != null)
+ ",F=" + numFailures + ",P=" + job.isPersisted()
- + ",ANI=" + appNotIdleConstraintSatisfied.get()
+ + ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
+ (isReady() ? "(READY)" : "")
+ "]";
}
@@ -349,6 +421,33 @@
return sb.toString();
}
+ void dumpConstraints(PrintWriter pw, int constraints) {
+ if ((constraints&CONSTRAINT_CHARGING) != 0) {
+ pw.print(" CHARGING");
+ }
+ if ((constraints&CONSTRAINT_TIMING_DELAY) != 0) {
+ pw.print(" TIMING_DELAY");
+ }
+ if ((constraints&CONSTRAINT_DEADLINE) != 0) {
+ pw.print(" DEADLINE");
+ }
+ if ((constraints&CONSTRAINT_IDLE) != 0) {
+ pw.print(" IDLE");
+ }
+ if ((constraints&CONSTRAINT_UNMETERED) != 0) {
+ pw.print(" UNMETERED");
+ }
+ if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
+ pw.print(" CONNECTIVITY");
+ }
+ if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
+ pw.print(" APP_NOT_IDLE");
+ }
+ if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
+ pw.print(" CONTENT_TRIGGER");
+ }
+ }
+
// Dumpsys infrastructure
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); UserHandle.formatUid(pw, callingUid);
@@ -413,39 +512,12 @@
if (job.hasLateConstraint()) {
pw.print(prefix); pw.println(" Has late constraint");
}
- pw.print(prefix); pw.println("Constraints:");
- if (hasChargingConstraint()) {
- pw.print(prefix); pw.print(" Charging: ");
- pw.println(chargingConstraintSatisfied.get());
- }
- if (hasTimingDelayConstraint()) {
- pw.print(prefix); pw.print(" Time delay: ");
- pw.println(timeDelayConstraintSatisfied.get());
- }
- if (hasDeadlineConstraint()) {
- pw.print(prefix); pw.print(" Deadline: ");
- pw.println(deadlineConstraintSatisfied.get());
- }
- if (hasIdleConstraint()) {
- pw.print(prefix); pw.print(" System idle: ");
- pw.println(idleConstraintSatisfied.get());
- }
- if (hasUnmeteredConstraint()) {
- pw.print(prefix); pw.print(" Unmetered: ");
- pw.println(unmeteredConstraintSatisfied.get());
- }
- if (hasConnectivityConstraint()) {
- pw.print(prefix); pw.print(" Connectivity: ");
- pw.println(connectivityConstraintSatisfied.get());
- }
- if (hasIdleConstraint()) {
- pw.print(prefix); pw.print(" App not idle: ");
- pw.println(appNotIdleConstraintSatisfied.get());
- }
- if (hasContentTriggerConstraint()) {
- pw.print(prefix); pw.print(" Content trigger: ");
- pw.println(contentTriggerConstraintSatisfied.get());
- }
+ pw.print(prefix); pw.print("Required constraints:");
+ dumpConstraints(pw, requiredConstraints);
+ pw.println();
+ pw.print(prefix); pw.print("Satisfied constraints:");
+ dumpConstraints(pw, satisfiedConstraints);
+ pw.println();
if (changedAuthorities != null) {
pw.print(prefix); pw.println("Changed authorities:");
for (int i=0; i<changedAuthorities.size(); i++) {
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index b619ea8..7882bc4d 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -30,13 +30,16 @@
*/
public abstract class StateController {
protected static final boolean DEBUG = JobSchedulerService.DEBUG;
- protected Context mContext;
- protected StateChangedListener mStateChangedListener;
+ protected final Context mContext;
+ protected final Object mLock;
+ protected final StateChangedListener mStateChangedListener;
protected boolean mDeviceIdleMode;
- public StateController(StateChangedListener stateChangedListener, Context context) {
+ public StateController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
mStateChangedListener = stateChangedListener;
mContext = context;
+ mLock = lock;
}
public void deviceIdleModeChanged(boolean enabled) {
@@ -49,21 +52,21 @@
* Also called when updating a task, so implementing controllers have to be aware of
* preexisting tasks.
*/
- public abstract void maybeStartTrackingJob(JobStatus jobStatus, JobStatus lastJob);
+ public abstract void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob);
/**
* Optionally implement logic here to prepare the job to be executed.
*/
- public void prepareForExecution(JobStatus jobStatus) {
+ public void prepareForExecutionLocked(JobStatus jobStatus) {
}
/**
* Remove task - this will happen if the task is cancelled, completed, etc.
*/
- public abstract void maybeStopTrackingJob(JobStatus jobStatus, boolean forUpdate);
+ public abstract void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate);
/**
* Called when a new job is being created to reschedule an old failed job.
*/
public void rescheduleForFailure(JobStatus newJob, JobStatus failureToReschedule) {
}
- public abstract void dumpControllerState(PrintWriter pw);
+ public abstract void dumpControllerStateLocked(PrintWriter pw);
}
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index a68c3ad..620800c 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -54,13 +54,14 @@
public static synchronized TimeController get(JobSchedulerService jms) {
if (mSingleton == null) {
- mSingleton = new TimeController(jms, jms.getContext());
+ mSingleton = new TimeController(jms, jms.getContext(), jms.getLock());
}
return mSingleton;
}
- private TimeController(StateChangedListener stateChangedListener, Context context) {
- super(stateChangedListener, context);
+ private TimeController(StateChangedListener stateChangedListener, Context context,
+ Object lock) {
+ super(stateChangedListener, context, lock);
mNextJobExpiredElapsedMillis = Long.MAX_VALUE;
mNextDelayExpiredElapsedMillis = Long.MAX_VALUE;
@@ -71,9 +72,9 @@
* list.
*/
@Override
- public synchronized void maybeStartTrackingJob(JobStatus job, JobStatus lastJob) {
+ public void maybeStartTrackingJobLocked(JobStatus job, JobStatus lastJob) {
if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
- maybeStopTrackingJob(job, false);
+ maybeStopTrackingJobLocked(job, false);
boolean isInsert = false;
ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
while (it.hasPrevious()) {
@@ -84,12 +85,11 @@
break;
}
}
- if(isInsert)
- {
+ if (isInsert) {
it.next();
}
it.add(job);
- maybeUpdateAlarms(
+ maybeUpdateAlarmsLocked(
job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE);
}
@@ -101,7 +101,7 @@
* Really an == comparison should be enough, but why play with fate? We'll do <=.
*/
@Override
- public synchronized void maybeStopTrackingJob(JobStatus job, boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus job, boolean forUpdate) {
if (mTrackedJobs.remove(job)) {
checkExpiredDelaysAndResetAlarm();
checkExpiredDeadlinesAndResetAlarm();
@@ -114,14 +114,14 @@
* the job's deadline is fulfilled - unlike other controllers a time constraint can't toggle
* back and forth.
*/
- private boolean canStopTrackingJob(JobStatus job) {
+ private boolean canStopTrackingJobLocked(JobStatus job) {
return (!job.hasTimingDelayConstraint() ||
- job.timeDelayConstraintSatisfied.get()) &&
+ (job.satisfiedConstraints&JobStatus.CONSTRAINT_TIMING_DELAY) != 0) &&
(!job.hasDeadlineConstraint() ||
- job.deadlineConstraintSatisfied.get());
+ (job.satisfiedConstraints&JobStatus.CONSTRAINT_DEADLINE) != 0);
}
- private void ensureAlarmService() {
+ private void ensureAlarmServiceLocked() {
if (mAlarmService == null) {
mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
}
@@ -131,71 +131,75 @@
* Checks list of jobs for ones that have an expired deadline, sending them to the JobScheduler
* if so, removing them from this list, and updating the alarm for the next expiry time.
*/
- private synchronized void checkExpiredDeadlinesAndResetAlarm() {
- long nextExpiryTime = Long.MAX_VALUE;
- final long nowElapsedMillis = SystemClock.elapsedRealtime();
+ private void checkExpiredDeadlinesAndResetAlarm() {
+ synchronized (mLock) {
+ long nextExpiryTime = Long.MAX_VALUE;
+ final long nowElapsedMillis = SystemClock.elapsedRealtime();
- Iterator<JobStatus> it = mTrackedJobs.iterator();
- while (it.hasNext()) {
- JobStatus job = it.next();
- if (!job.hasDeadlineConstraint()) {
- continue;
- }
- final long jobDeadline = job.getLatestRunTimeElapsed();
+ Iterator<JobStatus> it = mTrackedJobs.iterator();
+ while (it.hasNext()) {
+ JobStatus job = it.next();
+ if (!job.hasDeadlineConstraint()) {
+ continue;
+ }
+ final long jobDeadline = job.getLatestRunTimeElapsed();
- if (jobDeadline <= nowElapsedMillis) {
- job.deadlineConstraintSatisfied.set(true);
- mStateChangedListener.onRunJobNow(job);
- it.remove();
- } else { // Sorted by expiry time, so take the next one and stop.
- nextExpiryTime = jobDeadline;
- break;
+ if (jobDeadline <= nowElapsedMillis) {
+ job.setDeadlineConstraintSatisfied(true);
+ mStateChangedListener.onRunJobNow(job);
+ it.remove();
+ } else { // Sorted by expiry time, so take the next one and stop.
+ nextExpiryTime = jobDeadline;
+ break;
+ }
}
+ setDeadlineExpiredAlarmLocked(nextExpiryTime);
}
- setDeadlineExpiredAlarm(nextExpiryTime);
}
/**
* Handles alarm that notifies us that a job's delay has expired. Iterates through the list of
* tracked jobs and marks them as ready as appropriate.
*/
- private synchronized void checkExpiredDelaysAndResetAlarm() {
- final long nowElapsedMillis = SystemClock.elapsedRealtime();
- long nextDelayTime = Long.MAX_VALUE;
- boolean ready = false;
- Iterator<JobStatus> it = mTrackedJobs.iterator();
- while (it.hasNext()) {
- final JobStatus job = it.next();
- if (!job.hasTimingDelayConstraint()) {
- continue;
- }
- final long jobDelayTime = job.getEarliestRunTime();
- if (jobDelayTime <= nowElapsedMillis) {
- job.timeDelayConstraintSatisfied.set(true);
- if (canStopTrackingJob(job)) {
- it.remove();
+ private void checkExpiredDelaysAndResetAlarm() {
+ synchronized (mLock) {
+ final long nowElapsedMillis = SystemClock.elapsedRealtime();
+ long nextDelayTime = Long.MAX_VALUE;
+ boolean ready = false;
+ Iterator<JobStatus> it = mTrackedJobs.iterator();
+ while (it.hasNext()) {
+ final JobStatus job = it.next();
+ if (!job.hasTimingDelayConstraint()) {
+ continue;
}
- if (job.isReady()) {
- ready = true;
- }
- } else { // Keep going through list to get next delay time.
- if (nextDelayTime > jobDelayTime) {
- nextDelayTime = jobDelayTime;
+ final long jobDelayTime = job.getEarliestRunTime();
+ if (jobDelayTime <= nowElapsedMillis) {
+ job.setTimingDelayConstraintSatisfied(true);
+ if (canStopTrackingJobLocked(job)) {
+ it.remove();
+ }
+ if (job.isReady()) {
+ ready = true;
+ }
+ } else { // Keep going through list to get next delay time.
+ if (nextDelayTime > jobDelayTime) {
+ nextDelayTime = jobDelayTime;
+ }
}
}
+ if (ready) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ setDelayExpiredAlarmLocked(nextDelayTime);
}
- if (ready) {
- mStateChangedListener.onControllerStateChanged();
- }
- setDelayExpiredAlarm(nextDelayTime);
}
- private void maybeUpdateAlarms(long delayExpiredElapsed, long deadlineExpiredElapsed) {
+ private void maybeUpdateAlarmsLocked(long delayExpiredElapsed, long deadlineExpiredElapsed) {
if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
- setDelayExpiredAlarm(delayExpiredElapsed);
+ setDelayExpiredAlarmLocked(delayExpiredElapsed);
}
if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
- setDeadlineExpiredAlarm(deadlineExpiredElapsed);
+ setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed);
}
}
@@ -204,10 +208,11 @@
* delay will expire.
* This alarm <b>will</b> wake up the phone.
*/
- private void setDelayExpiredAlarm(long alarmTimeElapsedMillis) {
+ private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis) {
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
- updateAlarmWithListener(DELAY_TAG, mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis);
+ updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
+ mNextDelayExpiredElapsedMillis);
}
/**
@@ -215,10 +220,11 @@
* deadline will expire.
* This alarm <b>will</b> wake up the phone.
*/
- private void setDeadlineExpiredAlarm(long alarmTimeElapsedMillis) {
+ private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis) {
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
- updateAlarmWithListener(DEADLINE_TAG, mDeadlineExpiredListener, mNextJobExpiredElapsedMillis);
+ updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
+ mNextJobExpiredElapsedMillis);
}
private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
@@ -229,9 +235,9 @@
return proposedAlarmTimeElapsedMillis;
}
- private void updateAlarmWithListener(String tag, OnAlarmListener listener,
+ private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener,
long alarmTimeElapsed) {
- ensureAlarmService();
+ ensureAlarmServiceLocked();
if (alarmTimeElapsed == Long.MAX_VALUE) {
mAlarmService.cancel(listener);
} else {
@@ -266,7 +272,7 @@
};
@Override
- public void dumpControllerState(PrintWriter pw) {
+ public void dumpControllerStateLocked(PrintWriter pw) {
final long nowElapsed = SystemClock.elapsedRealtime();
pw.println("Alarms (" + SystemClock.elapsedRealtime() + ")");
pw.println(
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c1eb844..7fb1783 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1684,25 +1684,25 @@
/**
* Called from native code to inform us the hardware information.
*/
- private void setGpsYearOfHardware(int yearOfHardware) {
- if (DEBUG) Log.d(TAG, "setGpsYearOfHardware called with " + yearOfHardware);
+ private void setGnssYearOfHardware(int yearOfHardware) {
+ if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
mYearOfHardware = yearOfHardware;
}
- public interface GpsSystemInfoProvider {
+ public interface GnssSystemInfoProvider {
/**
* Returns the year of GPS hardware.
*/
- int getGpsYearOfHardware();
+ int getGnssYearOfHardware();
}
/**
* @hide
*/
- public GpsSystemInfoProvider getGpsSystemInfoProvider() {
- return new GpsSystemInfoProvider() {
+ public GnssSystemInfoProvider getGnssSystemInfoProvider() {
+ return new GnssSystemInfoProvider() {
@Override
- public int getGpsYearOfHardware() {
+ public int getGnssYearOfHardware() {
return mYearOfHardware;
}
};
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 246da2e..862c061 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -868,6 +868,38 @@
}
}
+ public void prepare() {
+ try {
+ mCb.onPrepare();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in prepare.", e);
+ }
+ }
+
+ public void prepareFromMediaId(String mediaId, Bundle extras) {
+ try {
+ mCb.onPrepareFromMediaId(mediaId, extras);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in prepareFromMediaId.", e);
+ }
+ }
+
+ public void prepareFromSearch(String query, Bundle extras) {
+ try {
+ mCb.onPrepareFromSearch(query, extras);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in prepareFromSearch.", e);
+ }
+ }
+
+ public void prepareFromUri(Uri uri, Bundle extras) {
+ try {
+ mCb.onPrepareFromUri(uri, extras);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote failure in prepareFromUri.", e);
+ }
+ }
+
public void play() {
try {
mCb.onPlay();
@@ -880,7 +912,7 @@
try {
mCb.onPlayFromMediaId(mediaId, extras);
} catch (RemoteException e) {
- Slog.e(TAG, "Remote failure in playUri.", e);
+ Slog.e(TAG, "Remote failure in playFromMediaId.", e);
}
}
@@ -1100,6 +1132,27 @@
}
@Override
+ public void prepare() throws RemoteException {
+ mSessionCb.prepare();
+ }
+
+ @Override
+ public void prepareFromMediaId(String mediaId, Bundle extras)
+ throws RemoteException {
+ mSessionCb.prepareFromMediaId(mediaId, extras);
+ }
+
+ @Override
+ public void prepareFromSearch(String query, Bundle extras) throws RemoteException {
+ mSessionCb.prepareFromSearch(query, extras);
+ }
+
+ @Override
+ public void prepareFromUri(Uri uri, Bundle extras) throws RemoteException {
+ mSessionCb.prepareFromUri(uri, extras);
+ }
+
+ @Override
public void play() throws RemoteException {
mSessionCb.play();
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index bc5b561..3421433 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1742,13 +1742,18 @@
public void setNetworkPolicies(NetworkPolicy[] policies) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- maybeRefreshTrustedTime();
- synchronized (mRulesLock) {
- normalizePoliciesLocked(policies);
- updateNetworkEnabledLocked();
- updateNetworkRulesLocked();
- updateNotificationsLocked();
- writePolicyLocked();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ maybeRefreshTrustedTime();
+ synchronized (mRulesLock) {
+ normalizePoliciesLocked(policies);
+ updateNetworkEnabledLocked();
+ updateNetworkRulesLocked();
+ updateNotificationsLocked();
+ writePolicyLocked();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
@@ -1851,13 +1856,18 @@
@Override
public void setRestrictBackground(boolean restrictBackground) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ maybeRefreshTrustedTime();
+ synchronized (mRulesLock) {
+ mRestrictBackground = restrictBackground;
+ updateRulesForGlobalChangeLocked(true);
+ updateNotificationsLocked();
+ writePolicyLocked();
+ }
- maybeRefreshTrustedTime();
- synchronized (mRulesLock) {
- mRestrictBackground = restrictBackground;
- updateRulesForGlobalChangeLocked(true);
- updateNotificationsLocked();
- writePolicyLocked();
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 5cd1025..a5dc008 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -211,12 +211,7 @@
if (enabled < 0) {
return enabled;
}
- final long token = Binder.clearCallingIdentity();
- try {
- mInterface.setRestrictBackground(enabled > 0);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mInterface.setRestrictBackground(enabled > 0);
return 0;
}
@@ -225,12 +220,7 @@
if (uid < 0) {
return uid;
}
- final long token = Binder.clearCallingIdentity();
- try {
- mInterface.addRestrictBackgroundWhitelistedUid(uid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mInterface.addRestrictBackgroundWhitelistedUid(uid);
return 0;
}
@@ -239,12 +229,7 @@
if (uid < 0) {
return uid;
}
- final long token = Binder.clearCallingIdentity();
- try {
- mInterface.removeRestrictBackgroundWhitelistedUid(uid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mInterface.removeRestrictBackgroundWhitelistedUid(uid);
return 0;
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
index 479b065..98fe770 100644
--- a/services/core/java/com/android/server/net/NetworkStatsAccess.java
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -17,6 +17,7 @@
package com.android.server.net;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
+import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
import static android.net.TrafficStats.UID_TETHERING;
@@ -48,6 +49,7 @@
@IntDef({
Level.DEFAULT,
Level.USER,
+ Level.DEVICESUMMARY,
Level.DEVICE,
})
@Retention(RetentionPolicy.SOURCE)
@@ -147,6 +149,12 @@
// Device-level access - can access usage for any uid.
return true;
case NetworkStatsAccess.Level.DEVICESUMMARY:
+ // Can access usage for any app running in the same user, along
+ // with some special uids (system, removed, or tethering) and
+ // anonymized uids
+ return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
+ || uid == UID_TETHERING || uid == UID_ALL
+ || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
case NetworkStatsAccess.Level.USER:
// User-level access - can access usage for any app running in the same user, along
// with some special uids (system, removed, or tethering).
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index eec7d93..d986e94b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -135,7 +135,11 @@
}
public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
- final int callerUid = Binder.getCallingUid();
+ return getRelevantUids(accessLevel, Binder.getCallingUid());
+ }
+
+ public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel,
+ final int callerUid) {
IntArray uids = new IntArray();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
@@ -169,7 +173,17 @@
public NetworkStatsHistory getHistory(
NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end,
@NetworkStatsAccess.Level int accessLevel) {
- final int callerUid = Binder.getCallingUid();
+ return getHistory(template, uid, set, tag, fields, start, end, accessLevel,
+ Binder.getCallingUid());
+ }
+
+ /**
+ * Combine all {@link NetworkStatsHistory} in this collection which match
+ * the requested parameters.
+ */
+ public NetworkStatsHistory getHistory(
+ NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel, int callerUid) {
if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) {
throw new SecurityException("Network stats history of uid " + uid
+ " is forbidden for caller " + callerUid);
@@ -198,6 +212,15 @@
*/
public NetworkStats getSummary(NetworkTemplate template, long start, long end,
@NetworkStatsAccess.Level int accessLevel) {
+ return getSummary(template, start, end, accessLevel, Binder.getCallingUid());
+ }
+
+ /**
+ * Summarize all {@link NetworkStatsHistory} in this collection which match
+ * the requested parameters.
+ */
+ public NetworkStats getSummary(NetworkTemplate template, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel, int callerUid) {
final long now = System.currentTimeMillis();
final NetworkStats stats = new NetworkStats(end - start, 24);
@@ -207,7 +230,6 @@
final NetworkStats.Entry entry = new NetworkStats.Entry();
NetworkStatsHistory.Entry historyEntry = null;
- final int callerUid = Binder.getCallingUid();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
if (templateMatches(template, key.ident)
diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java
new file mode 100644
index 0000000..2f55562
--- /dev/null
+++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java
@@ -0,0 +1,493 @@
+/*
+ * 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.net;
+
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.app.usage.NetworkStatsManager;
+import android.net.DataUsageRequest;
+import android.net.NetworkStats;
+import android.net.NetworkStats.NonMonotonicObserver;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.IntArray;
+import android.util.SparseArray;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.VpnInfo;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Manages observers of {@link NetworkStats}. Allows observers to be notified when
+ * data usage has been reported in {@link NetworkStatsService}. An observer can set
+ * a threshold of how much data it cares about to be notified.
+ */
+class NetworkStatsObservers {
+ private static final String TAG = "NetworkStatsObservers";
+ private static final boolean LOGV = true;
+
+ private static final long MIN_THRESHOLD_BYTES = 2 * MB_IN_BYTES;
+
+ private static final int MSG_REGISTER = 1;
+ private static final int MSG_UNREGISTER = 2;
+ private static final int MSG_UPDATE_STATS = 3;
+
+ // All access to this map must be done from the handler thread.
+ // indexed by DataUsageRequest#requestId
+ private final SparseArray<RequestInfo> mDataUsageRequests = new SparseArray<>();
+
+ // Sequence number of DataUsageRequests
+ private final AtomicInteger mNextDataUsageRequestId = new AtomicInteger();
+
+ // Lazily instantiated when an observer is registered.
+ private Handler mHandler;
+
+ /**
+ * Creates a wrapper that contains the caller context and a normalized request.
+ * The request should be returned to the caller app, and the wrapper should be sent to this
+ * object through #addObserver by the service handler.
+ *
+ * <p>It will register the observer asynchronously, so it is safe to call from any thread.
+ *
+ * @return the normalized request wrapped within {@link RequestInfo}.
+ */
+ public DataUsageRequest register(DataUsageRequest inputRequest, Messenger messenger,
+ IBinder binder, int callingUid, @NetworkStatsAccess.Level int accessLevel) {
+ checkVisibilityUids(callingUid, accessLevel, inputRequest.uids);
+
+ DataUsageRequest request = buildRequest(inputRequest);
+ RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid,
+ accessLevel);
+
+ if (LOGV) Slog.v(TAG, "Registering observer for " + request);
+ getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo));
+ return request;
+ }
+
+ /**
+ * Unregister a data usage observer.
+ *
+ * <p>It will unregister the observer asynchronously, so it is safe to call from any thread.
+ */
+ public void unregister(DataUsageRequest request, int callingUid) {
+ getHandler().sendMessage(mHandler.obtainMessage(MSG_UNREGISTER, callingUid, 0 /* ignore */,
+ request));
+ }
+
+ /**
+ * Updates data usage statistics of registered observers and notifies if limits are reached.
+ *
+ * <p>It will update stats asynchronously, so it is safe to call from any thread.
+ */
+ public void updateStats(NetworkStats xtSnapshot, NetworkStats uidSnapshot,
+ ArrayMap<String, NetworkIdentitySet> activeIfaces,
+ ArrayMap<String, NetworkIdentitySet> activeUidIfaces,
+ VpnInfo[] vpnArray, long currentTime) {
+ StatsContext statsContext = new StatsContext(xtSnapshot, uidSnapshot, activeIfaces,
+ activeUidIfaces, vpnArray, currentTime);
+ getHandler().sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATS, statsContext));
+ }
+
+ private Handler getHandler() {
+ if (mHandler == null) {
+ synchronized (this) {
+ if (mHandler == null) {
+ if (LOGV) Slog.v(TAG, "Creating handler");
+ mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback);
+ }
+ }
+ }
+ return mHandler;
+ }
+
+ @VisibleForTesting
+ protected Looper getHandlerLooperLocked() {
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ return handlerThread.getLooper();
+ }
+
+ private Handler.Callback mHandlerCallback = new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_REGISTER: {
+ handleRegister((RequestInfo) msg.obj);
+ return true;
+ }
+ case MSG_UNREGISTER: {
+ handleUnregister((DataUsageRequest) msg.obj, msg.arg1 /* callingUid */);
+ return true;
+ }
+ case MSG_UPDATE_STATS: {
+ handleUpdateStats((StatsContext) msg.obj);
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+ }
+ };
+
+ /**
+ * Adds a {@link RequestInfo} as an observer.
+ * Should only be called from the handler thread otherwise there will be a race condition
+ * on mDataUsageRequests.
+ */
+ private void handleRegister(RequestInfo requestInfo) {
+ mDataUsageRequests.put(requestInfo.mRequest.requestId, requestInfo);
+ }
+
+ /**
+ * Removes a {@link DataUsageRequest} if the calling uid is authorized.
+ * Should only be called from the handler thread otherwise there will be a race condition
+ * on mDataUsageRequests.
+ */
+ private void handleUnregister(DataUsageRequest request, int callingUid) {
+ RequestInfo requestInfo;
+ requestInfo = mDataUsageRequests.get(request.requestId);
+ if (requestInfo == null) {
+ if (LOGV) Slog.v(TAG, "Trying to unregister unknown request " + request);
+ return;
+ }
+ if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) {
+ Slog.w(TAG, "Caller uid " + callingUid + " is not owner of " + request);
+ return;
+ }
+
+ if (LOGV) Slog.v(TAG, "Unregistering " + request);
+ mDataUsageRequests.remove(request.requestId);
+ requestInfo.unlinkDeathRecipient();
+ requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED);
+ }
+
+ private void handleUpdateStats(StatsContext statsContext) {
+ if (mDataUsageRequests.size() == 0) {
+ if (LOGV) Slog.v(TAG, "No registered listeners of data usage");
+ return;
+ }
+
+ if (LOGV) Slog.v(TAG, "Checking if any registered observer needs to be notified");
+ for (int i = 0; i < mDataUsageRequests.size(); i++) {
+ RequestInfo requestInfo = mDataUsageRequests.valueAt(i);
+ requestInfo.updateStats(statsContext);
+ }
+ }
+
+ private DataUsageRequest buildRequest(DataUsageRequest request) {
+ // Cap the minimum threshold to a safe default to avoid too many callbacks
+ long thresholdInBytes = Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes);
+ if (thresholdInBytes < request.thresholdInBytes) {
+ Slog.w(TAG, "Threshold was too low for " + request
+ + ". Overriding to a safer default of " + thresholdInBytes + " bytes");
+ }
+ return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(),
+ request.templates, request.uids, thresholdInBytes);
+ }
+
+ private RequestInfo buildRequestInfo(DataUsageRequest request,
+ Messenger messenger, IBinder binder, int callingUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ if (accessLevel <= NetworkStatsAccess.Level.USER
+ || request.uids != null && request.uids.length > 0) {
+ return new UserUsageRequestInfo(this, request, messenger, binder, callingUid,
+ accessLevel);
+ } else {
+ // Safety check in case a new access level is added and we forgot to update this
+ checkArgument(accessLevel >= NetworkStatsAccess.Level.DEVICESUMMARY);
+ return new NetworkUsageRequestInfo(this, request, messenger, binder, callingUid,
+ accessLevel);
+ }
+ }
+
+ private void checkVisibilityUids(int callingUid, @NetworkStatsAccess.Level int accessLevel,
+ int[] uids) {
+ if (uids == null) {
+ return;
+ }
+ for (int i = 0; i < uids.length; i++) {
+ if (!NetworkStatsAccess.isAccessibleToUser(uids[i], callingUid, accessLevel)) {
+ throw new SecurityException("Caller " + callingUid + " cannot monitor network stats"
+ + " for uid " + uids[i] + " with accessLevel " + accessLevel);
+ }
+ }
+ }
+
+ /**
+ * Tracks information relevant to a data usage observer.
+ * It will notice when the calling process dies so we can self-expire.
+ */
+ private abstract static class RequestInfo implements IBinder.DeathRecipient {
+ private final NetworkStatsObservers mStatsObserver;
+ protected final DataUsageRequest mRequest;
+ private final Messenger mMessenger;
+ private final IBinder mBinder;
+ protected final int mCallingUid;
+ protected final @NetworkStatsAccess.Level int mAccessLevel;
+ protected NetworkStatsRecorder mRecorder;
+ protected NetworkStatsCollection mCollection;
+
+ RequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
+ Messenger messenger, IBinder binder, int callingUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ mStatsObserver = statsObserver;
+ mRequest = request;
+ mMessenger = messenger;
+ mBinder = binder;
+ mCallingUid = callingUid;
+ mAccessLevel = accessLevel;
+
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ if (LOGV) Slog.v(TAG, "RequestInfo binderDied("
+ + mRequest + ", " + mBinder + ")");
+ mStatsObserver.unregister(mRequest, Process.SYSTEM_UID);
+ callCallback(NetworkStatsManager.CALLBACK_RELEASED);
+ }
+
+ @Override
+ public String toString() {
+ return "RequestInfo from uid:" + mCallingUid
+ + " for " + mRequest + " accessLevel:" + mAccessLevel;
+ }
+
+ private void unlinkDeathRecipient() {
+ if (mBinder != null) {
+ mBinder.unlinkToDeath(this, 0);
+ }
+ }
+
+ /**
+ * Update stats given the samples and interface to identity mappings.
+ */
+ private void updateStats(StatsContext statsContext) {
+ if (mRecorder == null) {
+ // First run; establish baseline stats
+ resetRecorder();
+ recordSample(statsContext);
+ return;
+ }
+ recordSample(statsContext);
+
+ if (checkStats()) {
+ resetRecorder();
+ callCallback(NetworkStatsManager.CALLBACK_LIMIT_REACHED);
+ }
+ }
+
+ private void callCallback(int callbackType) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(DataUsageRequest.PARCELABLE_KEY, mRequest);
+ Message msg = Message.obtain();
+ msg.what = callbackType;
+ msg.setData(bundle);
+ try {
+ if (LOGV) {
+ Slog.v(TAG, "sending notification " + callbackTypeToName(callbackType)
+ + " for " + mRequest);
+ }
+ mMessenger.send(msg);
+ } catch (RemoteException e) {
+ // May occur naturally in the race of binder death.
+ Slog.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest);
+ }
+ }
+
+ private void resetRecorder() {
+ mRecorder = new NetworkStatsRecorder();
+ mCollection = mRecorder.getSinceBoot();
+ }
+
+ protected abstract boolean checkStats();
+
+ protected abstract void recordSample(StatsContext statsContext);
+
+ private String callbackTypeToName(int callbackType) {
+ switch (callbackType) {
+ case NetworkStatsManager.CALLBACK_LIMIT_REACHED:
+ return "LIMIT_REACHED";
+ case NetworkStatsManager.CALLBACK_RELEASED:
+ return "RELEASED";
+ default:
+ return "UNKNOWN";
+ }
+ }
+ }
+
+ private static class NetworkUsageRequestInfo extends RequestInfo {
+ NetworkUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
+ Messenger messenger, IBinder binder, int callingUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ super(statsObserver, request, messenger, binder, callingUid, accessLevel);
+ }
+
+ @Override
+ protected boolean checkStats() {
+ for (int i = 0; i < mRequest.templates.length; i++) {
+ long bytesSoFar = getTotalBytesForNetwork(mRequest.templates[i]);
+ if (LOGV) {
+ Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
+ + mRequest.templates[i]);
+ }
+ if (bytesSoFar > mRequest.thresholdInBytes) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void recordSample(StatsContext statsContext) {
+ // Recorder does not need to be locked in this context since only the handler
+ // thread will update it
+ mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces,
+ statsContext.mVpnArray, statsContext.mCurrentTime);
+ }
+
+ /**
+ * Reads stats matching the given template. {@link NetworkStatsCollection} will aggregate
+ * over all buckets, which in this case should be only one since we built it big enough
+ * that it will outlive the caller. If it doesn't, then there will be multiple buckets.
+ */
+ private long getTotalBytesForNetwork(NetworkTemplate template) {
+ NetworkStats stats = mCollection.getSummary(template,
+ Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */,
+ mAccessLevel, mCallingUid);
+ if (LOGV) {
+ Slog.v(TAG, "Netstats for " + template + ": " + stats);
+ }
+ return stats.getTotalBytes();
+ }
+ }
+
+ private static class UserUsageRequestInfo extends RequestInfo {
+ UserUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request,
+ Messenger messenger, IBinder binder, int callingUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ super(statsObserver, request, messenger, binder, callingUid, accessLevel);
+ }
+
+ @Override
+ protected boolean checkStats() {
+ int[] uidsToMonitor = getUidsToMonitor();
+
+ for (int i = 0; i < mRequest.templates.length; i++) {
+ for (int j = 0; j < uidsToMonitor.length; j++) {
+ long bytesSoFar = getTotalBytesForNetworkUid(mRequest.templates[i],
+ uidsToMonitor[j]);
+
+ if (LOGV) {
+ Slog.v(TAG, bytesSoFar + " bytes so far since notification for "
+ + mRequest.templates[i] + " for uid=" + uidsToMonitor[j]);
+ }
+ if (bytesSoFar > mRequest.thresholdInBytes) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void recordSample(StatsContext statsContext) {
+ // Recorder does not need to be locked in this context since only the handler
+ // thread will update it
+ mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces,
+ statsContext.mVpnArray, statsContext.mCurrentTime);
+ }
+
+ /**
+ * Reads all stats matching the given template and uid. Ther history will likely only
+ * contain one bucket per ident since we build it big enough that it will outlive the
+ * caller lifetime.
+ */
+ private long getTotalBytesForNetworkUid(NetworkTemplate template, int uid) {
+ try {
+ NetworkStatsHistory history = mCollection.getHistory(template, uid,
+ NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
+ NetworkStatsHistory.FIELD_ALL,
+ Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */,
+ mAccessLevel, mCallingUid);
+ return history.getTotalBytes();
+ } catch (SecurityException e) {
+ if (LOGV) {
+ Slog.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid "
+ + uid);
+ }
+ return 0;
+ }
+ }
+
+ private int[] getUidsToMonitor() {
+ if (mRequest.uids == null || mRequest.uids.length == 0) {
+ return mCollection.getRelevantUids(mAccessLevel, mCallingUid);
+ }
+ // Pick only uids from the request that are currently accessible to the user
+ IntArray accessibleUids = new IntArray(mRequest.uids.length);
+ for (int i = 0; i < mRequest.uids.length; i++) {
+ int uid = mRequest.uids[i];
+ if (NetworkStatsAccess.isAccessibleToUser(uid, mCallingUid, mAccessLevel)) {
+ accessibleUids.add(uid);
+ }
+ }
+ return accessibleUids.toArray();
+ }
+ }
+
+ private static class StatsContext {
+ NetworkStats mXtSnapshot;
+ NetworkStats mUidSnapshot;
+ ArrayMap<String, NetworkIdentitySet> mActiveIfaces;
+ ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces;
+ VpnInfo[] mVpnArray;
+ long mCurrentTime;
+
+ StatsContext(NetworkStats xtSnapshot, NetworkStats uidSnapshot,
+ ArrayMap<String, NetworkIdentitySet> activeIfaces,
+ ArrayMap<String, NetworkIdentitySet> activeUidIfaces,
+ VpnInfo[] vpnArray, long currentTime) {
+ mXtSnapshot = xtSnapshot;
+ mUidSnapshot = uidSnapshot;
+ mActiveIfaces = activeIfaces;
+ mActiveUidIfaces = activeUidIfaces;
+ mVpnArray = vpnArray;
+ mCurrentTime = currentTime;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index c091960..04dc917 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -19,6 +19,7 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.text.format.DateUtils.YEAR_IN_MILLIS;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.net.NetworkStats;
@@ -54,7 +55,7 @@
* Logic to record deltas between periodic {@link NetworkStats} snapshots into
* {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
* Keeps pending changes in memory until they pass a specific threshold, in
- * bytes. Uses {@link FileRotator} for persistence logic.
+ * bytes. Uses {@link FileRotator} for persistence logic if present.
* <p>
* Not inherently thread safe.
*/
@@ -86,6 +87,29 @@
private WeakReference<NetworkStatsCollection> mComplete;
+ /**
+ * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}.
+ */
+ public NetworkStatsRecorder() {
+ mRotator = null;
+ mObserver = null;
+ mDropBox = null;
+ mCookie = null;
+
+ // set the bucket big enough to have all data in one bucket, but allow some
+ // slack to avoid overflow
+ mBucketDuration = YEAR_IN_MILLIS;
+ mOnlyTags = false;
+
+ mPending = null;
+ mSinceBoot = new NetworkStatsCollection(mBucketDuration);
+
+ mPendingRewriter = null;
+ }
+
+ /**
+ * Persisted recorder.
+ */
public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
mRotator = checkNotNull(rotator, "missing FileRotator");
@@ -110,9 +134,15 @@
public void resetLocked() {
mLastSnapshot = null;
- mPending.reset();
- mSinceBoot.reset();
- mComplete.clear();
+ if (mPending != null) {
+ mPending.reset();
+ }
+ if (mSinceBoot != null) {
+ mSinceBoot.reset();
+ }
+ if (mComplete != null) {
+ mComplete.clear();
+ }
}
public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
@@ -120,6 +150,10 @@
NetworkStatsAccess.Level.DEVICE).getTotal(null);
}
+ public NetworkStatsCollection getSinceBoot() {
+ return mSinceBoot;
+ }
+
/**
* Load complete history represented by {@link FileRotator}. Caches
* internally as a {@link WeakReference}, and updated with future
@@ -127,6 +161,7 @@
* as reference is valid.
*/
public NetworkStatsCollection getOrLoadCompleteLocked() {
+ checkNotNull(mRotator, "missing FileRotator");
NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
if (res == null) {
res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
@@ -136,6 +171,7 @@
}
public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
+ checkNotNull(mRotator, "missing FileRotator");
NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
if (res == null) {
res = loadLocked(start, end);
@@ -205,7 +241,9 @@
// only record tag data when requested
if ((entry.tag == TAG_NONE) != mOnlyTags) {
- mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+ if (mPending != null) {
+ mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+ }
// also record against boot stats when present
if (mSinceBoot != null) {
@@ -231,6 +269,7 @@
* {@link #mPersistThresholdBytes}.
*/
public void maybePersistLocked(long currentTimeMillis) {
+ checkNotNull(mRotator, "missing FileRotator");
final long pendingBytes = mPending.getTotalBytes();
if (pendingBytes >= mPersistThresholdBytes) {
forcePersistLocked(currentTimeMillis);
@@ -243,6 +282,7 @@
* Force persisting any pending deltas.
*/
public void forcePersistLocked(long currentTimeMillis) {
+ checkNotNull(mRotator, "missing FileRotator");
if (mPending.isDirty()) {
if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
try {
@@ -264,20 +304,26 @@
* to {@link TrafficStats#UID_REMOVED}.
*/
public void removeUidsLocked(int[] uids) {
- try {
- // Rewrite all persisted data to migrate UID stats
- mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
- } catch (IOException e) {
- Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
- recoverFromWtf();
- } catch (OutOfMemoryError e) {
- Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
- recoverFromWtf();
+ if (mRotator != null) {
+ try {
+ // Rewrite all persisted data to migrate UID stats
+ mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
+ } catch (IOException e) {
+ Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
+ recoverFromWtf();
+ } catch (OutOfMemoryError e) {
+ Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
+ recoverFromWtf();
+ }
}
// Remove any pending stats
- mPending.removeUids(uids);
- mSinceBoot.removeUids(uids);
+ if (mPending != null) {
+ mPending.removeUids(uids);
+ }
+ if (mSinceBoot != null) {
+ mSinceBoot.removeUids(uids);
+ }
// Clear UID from current stats snapshot
if (mLastSnapshot != null) {
@@ -361,6 +407,8 @@
}
public void importLegacyNetworkLocked(File file) throws IOException {
+ checkNotNull(mRotator, "missing FileRotator");
+
// legacy file still exists; start empty to avoid double importing
mRotator.deleteAll();
@@ -379,6 +427,8 @@
}
public void importLegacyUidLocked(File file) throws IOException {
+ checkNotNull(mRotator, "missing FileRotator");
+
// legacy file still exists; start empty to avoid double importing
mRotator.deleteAll();
@@ -397,7 +447,9 @@
}
public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
- pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
+ if (mPending != null) {
+ pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
+ }
if (fullHistory) {
pw.println("Complete history:");
getOrLoadCompleteLocked().dump(pw);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 3aeceef..2c2e9b9 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -57,6 +57,7 @@
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
@@ -72,6 +73,7 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.net.DataUsageRequest;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
@@ -90,8 +92,10 @@
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Message;
+import android.os.Messenger;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -152,6 +156,7 @@
private final TrustedTime mTime;
private final TelephonyManager mTeleManager;
private final NetworkStatsSettings mSettings;
+ private final NetworkStatsObservers mStatsObservers;
private final File mSystemDir;
private final File mBaseDir;
@@ -233,43 +238,65 @@
/** Data layer operation counters for splicing into other structures. */
private NetworkStats mUidOperations = new NetworkStats(0L, 10);
- private final Handler mHandler;
+ /** Must be set in factory by calling #setHandler. */
+ private Handler mHandler;
+ private Handler.Callback mHandlerCallback;
private boolean mSystemReady;
private long mPersistThreshold = 2 * MB_IN_BYTES;
private long mGlobalAlertBytes;
- public NetworkStatsService(
- Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
- this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
- getDefaultSystemDir(), new DefaultNetworkStatsSettings(context));
- }
-
private static File getDefaultSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}
- public NetworkStatsService(Context context, INetworkManagementService networkManager,
- IAlarmManager alarmManager, TrustedTime time, File systemDir,
- NetworkStatsSettings settings) {
+ private static File getDefaultBaseDir() {
+ File baseDir = new File(getDefaultSystemDir(), "netstats");
+ baseDir.mkdirs();
+ return baseDir;
+ }
+
+ public static NetworkStatsService create(Context context,
+ INetworkManagementService networkManager) {
+ AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ PowerManager.WakeLock wakeLock =
+ powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager,
+ wakeLock, NtpTrustedTime.getInstance(context), TelephonyManager.getDefault(),
+ new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(),
+ getDefaultSystemDir(), getDefaultBaseDir());
+
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ Handler.Callback callback = new HandlerCallback(service);
+ handlerThread.start();
+ Handler handler = new Handler(handlerThread.getLooper(), callback);
+ service.setHandler(handler, callback);
+ return service;
+ }
+
+ @VisibleForTesting
+ NetworkStatsService(Context context, INetworkManagementService networkManager,
+ AlarmManager alarmManager, PowerManager.WakeLock wakeLock, TrustedTime time,
+ TelephonyManager teleManager, NetworkStatsSettings settings,
+ NetworkStatsObservers statsObservers, File systemDir, File baseDir) {
mContext = checkNotNull(context, "missing Context");
mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
+ mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager");
mTime = checkNotNull(time, "missing TrustedTime");
- mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager");
mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
- mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ mTeleManager = checkNotNull(teleManager, "missing TelephonyManager");
+ mWakeLock = checkNotNull(wakeLock, "missing WakeLock");
+ mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
+ mSystemDir = checkNotNull(systemDir, "missing systemDir");
+ mBaseDir = checkNotNull(baseDir, "missing baseDir");
+ }
- final PowerManager powerManager = (PowerManager) context.getSystemService(
- Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
- HandlerThread thread = new HandlerThread(TAG);
- thread.start();
- mHandler = new Handler(thread.getLooper(), mHandlerCallback);
-
- mSystemDir = checkNotNull(systemDir);
- mBaseDir = new File(systemDir, "netstats");
- mBaseDir.mkdirs();
+ @VisibleForTesting
+ void setHandler(Handler handler, Handler.Callback callback) {
+ mHandler = handler;
+ mHandlerCallback = callback;
}
public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -733,6 +760,46 @@
registerGlobalAlert();
}
+ @Override
+ public DataUsageRequest registerDataUsageCallback(String callingPackage,
+ DataUsageRequest request, Messenger messenger, IBinder binder) {
+ checkNotNull(callingPackage, "calling package is null");
+ checkNotNull(request, "DataUsageRequest is null");
+ checkNotNull(request.templates, "NetworkTemplate is null");
+ checkArgument(request.templates.length > 0);
+ checkNotNull(messenger, "messenger is null");
+ checkNotNull(binder, "binder is null");
+
+ int callingUid = Binder.getCallingUid();
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage);
+ DataUsageRequest normalizedRequest;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ normalizedRequest = mStatsObservers.register(request, messenger, binder,
+ callingUid, accessLevel);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ // Create baseline stats
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL, FLAG_PERSIST_ALL));
+
+ return normalizedRequest;
+ }
+
+ @Override
+ public void unregisterDataUsageRequest(DataUsageRequest request) {
+ checkNotNull(request, "DataUsageRequest is null");
+
+ int callingUid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mStatsObservers.unregister(request, callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
/**
* Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to
* reflect current {@link #mPersistThreshold} value. Always defers to
@@ -945,6 +1012,11 @@
mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, null, currentTime);
mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime);
+
+ // We need to make copies of member fields that are sent to the observer to avoid
+ // a race condition between the service handler thread and the observer's
+ mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces),
+ new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime);
}
/**
@@ -1243,21 +1315,28 @@
}
}
- private Handler.Callback mHandlerCallback = new Handler.Callback() {
+ @VisibleForTesting
+ static class HandlerCallback implements Handler.Callback {
+ private final NetworkStatsService mService;
+
+ HandlerCallback(NetworkStatsService service) {
+ this.mService = service;
+ }
+
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_PERFORM_POLL: {
final int flags = msg.arg1;
- performPoll(flags);
+ mService.performPoll(flags);
return true;
}
case MSG_UPDATE_IFACES: {
- updateIfaces();
+ mService.updateIfaces();
return true;
}
case MSG_REGISTER_GLOBAL_ALERT: {
- registerGlobalAlert();
+ mService.registerGlobalAlert();
return true;
}
default: {
@@ -1265,7 +1344,7 @@
}
}
}
- };
+ }
private void assertBandwidthControlEnabled() {
if (!isBandwidthControlEnabled()) {
diff --git a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java b/services/core/java/com/android/server/notification/ImportanceExtractor.java
similarity index 84%
rename from services/core/java/com/android/server/notification/TopicImportanceExtractor.java
rename to services/core/java/com/android/server/notification/ImportanceExtractor.java
index c6b3e0f..885b9b7 100644
--- a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
+++ b/services/core/java/com/android/server/notification/ImportanceExtractor.java
@@ -21,7 +21,7 @@
/**
* Determines the importance of the given notification.
*/
-public class TopicImportanceExtractor implements NotificationSignalExtractor {
+public class ImportanceExtractor implements NotificationSignalExtractor {
private static final String TAG = "ImportantTopicExtractor";
private static final boolean DBG = false;
@@ -42,9 +42,8 @@
return null;
}
- final int topicImportance = mConfig.getImportance(record.sbn.getPackageName(),
- record.sbn.getUid(), record.sbn.getNotification().getTopic());
- record.setTopicImportance(topicImportance);
+ record.setUserImportance(
+ mConfig.getImportance(record.sbn.getPackageName(), record.sbn.getUid()));
return null;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ede1a2f..95198a3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -30,7 +30,6 @@
import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED;
import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_SUSPENDED;
import static android.service.notification.NotificationAssistantService.REASON_PROFILE_TURNED_OFF;
-import static android.service.notification.NotificationAssistantService.REASON_TOPIC_BANNED;
import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
@@ -754,7 +753,7 @@
for (String pkgName : pkgList) {
if (cancelNotifications) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
- changeUserId, reason, null, null);
+ changeUserId, reason, null);
}
}
}
@@ -787,14 +786,14 @@
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userHandle >= 0) {
cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
- REASON_USER_STOPPED, null, null);
+ REASON_USER_STOPPED, null);
}
} else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
boolean inQuietMode = intent.getBooleanExtra(Intent.EXTRA_QUIET_MODE, false);
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (inQuietMode && userHandle >= 0) {
cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
- REASON_PROFILE_TURNED_OFF, null, null);
+ REASON_PROFILE_TURNED_OFF, null);
}
} else if (action.equals(Intent.ACTION_USER_PRESENT)) {
// turn off LED when user passes through lock screen
@@ -1086,7 +1085,7 @@
// Now, cancel any outstanding notifications that are part of a just-disabled app
if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
- REASON_PACKAGE_BANNED, null, null);
+ REASON_PACKAGE_BANNED, null);
}
}
@@ -1250,7 +1249,7 @@
// running foreground services.
cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
- REASON_APP_CANCEL_ALL, null, null);
+ REASON_APP_CANCEL_ALL, null);
}
@Override
@@ -1279,79 +1278,50 @@
}
@Override
- public boolean hasBannedTopics(String pkg, int uid) {
+ public void setPriority(String pkg, int uid, int priority) {
checkCallerIsSystem();
- return mRankingHelper.hasBannedTopics(pkg, uid);
- }
-
- @Override
- public ParceledListSlice<Notification.Topic> getTopics(String pkg, int uid) {
- checkCallerIsSystem();
- return new ParceledListSlice<Notification.Topic>(mRankingHelper.getTopics(pkg, uid));
- }
-
- @Override
- public void setPriority(String pkg, int uid, Notification.Topic topic, int priority) {
- checkCallerIsSystem();
- mRankingHelper.setPriority(pkg, uid, topic, priority);
+ mRankingHelper.setPriority(pkg, uid, priority);
savePolicyFile();
}
@Override
- public int getPriority(String pkg, int uid, Notification.Topic topic) {
+ public int getPriority(String pkg, int uid) {
checkCallerIsSystem();
- return mRankingHelper.getPriority(pkg, uid, topic);
+ return mRankingHelper.getPriority(pkg, uid);
}
@Override
- public void setVisibilityOverride(String pkg, int uid, Notification.Topic topic,
- int visibility) {
+ public void setVisibilityOverride(String pkg, int uid, int visibility) {
checkCallerIsSystem();
- mRankingHelper.setVisibilityOverride(pkg, uid, topic, visibility);
+ mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
savePolicyFile();
}
@Override
- public int getVisibilityOverride(String pkg, int uid, Notification.Topic topic) {
+ public int getVisibilityOverride(String pkg, int uid) {
checkCallerIsSystem();
- return mRankingHelper.getVisibilityOverride(pkg, uid, topic);
+ return mRankingHelper.getVisibilityOverride(pkg, uid);
}
@Override
- public void setImportance(String pkg, int uid, Notification.Topic topic,
- int importance) {
+ public void setImportance(String pkg, int uid, int importance) {
enforceSystemOrSystemUI("Caller not system or systemui");
- if (topic == null) {
- // App wide, potentially store block in app ops.
- setNotificationsEnabledForPackageImpl(pkg, uid,
- importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
- } else {
- if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) {
- cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true,
- UserHandle.getUserId(uid),
- REASON_TOPIC_BANNED, topic, null);
- }
- }
- mRankingHelper.setImportance(pkg, uid, topic, importance);
+ setNotificationsEnabledForPackageImpl(pkg, uid,
+ importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
+ mRankingHelper.setImportance(pkg, uid, importance);
savePolicyFile();
}
@Override
- public int getTopicImportance(String pkg, String topicId) {
+ public int getPackageImportance(String pkg) {
checkCallerIsSystemOrSameApp(pkg);
- return mRankingHelper.getImportance(pkg, Binder.getCallingUid(), topicId);
+ return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
}
@Override
- public int getImportance(String pkg, int uid, Notification.Topic topic) {
+ public int getImportance(String pkg, int uid) {
checkCallerIsSystem();
- return mRankingHelper.getImportance(pkg, uid, topic);
- }
-
- @Override
- public boolean doesUserUseTopics(String pkg, int uid) {
- enforceSystemOrSystemUI("Caller not system or systemui");
- return mRankingHelper.doesUserUseTopics(pkg, uid);
+ return mRankingHelper.getImportance(pkg, uid);
}
/**
@@ -2381,11 +2351,9 @@
mRankingHelper.extractSignals(r);
- // why is this here?
- savePolicyFile();
final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
- // blocked apps/topics
+ // blocked apps
if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
|| !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
if (!isSystemNotification) {
@@ -3182,11 +3150,11 @@
}
/**
- * Cancels all notifications from a given package or topic that have all of the
+ * Cancels all notifications from a given package that have all of the
* {@code mustHaveFlags}.
*/
boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
- int mustNotHaveFlags, boolean doit, int userId, int reason, Notification.Topic topic,
+ int mustNotHaveFlags, boolean doit, int userId, int reason,
ManagedServiceInfo listener) {
String listenerName = listener == null ? null : listener.component.toShortString();
EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
@@ -3214,10 +3182,6 @@
if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
continue;
}
- if (topic != null
- && !topic.getId().equals(r.getNotification().getTopic().getId())) {
- continue;
- }
if (canceledNotifications == null) {
canceledNotifications = new ArrayList<>();
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 12c70a3..25d17f6 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -35,7 +35,6 @@
import android.service.notification.StatusBarNotification;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
@@ -92,12 +91,12 @@
private int mAuthoritativeRank;
private String mGlobalSortKey;
private int mPackageVisibility;
- private int mTopicImportance = IMPORTANCE_UNSPECIFIED;
+ private int mUserImportance = IMPORTANCE_UNSPECIFIED;
private int mImportance = IMPORTANCE_UNSPECIFIED;
private CharSequence mImportanceExplanation = null;
private int mSuppressedVisualEffects = 0;
- private String mTopicExplanation;
+ private String mUserExplanation;
private String mPeopleExplanation;
@VisibleForTesting
@@ -149,8 +148,9 @@
}
try {
- final ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(
- sbn.getPackageName(), 0);
+ final ApplicationInfo applicationInfo =
+ mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
+ 0, sbn.getUser().getIdentifier());
if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.N) {
if (isNoisy) {
if (importance >= IMPORTANCE_HIGH) {
@@ -182,7 +182,7 @@
mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
mCreationTimeMs = previous.mCreationTimeMs;
mVisibleSinceMs = previous.mVisibleSinceMs;
- mTopicImportance = previous.mTopicImportance;
+ mUserImportance = previous.mUserImportance;
mImportance = previous.mImportance;
mImportanceExplanation = previous.mImportanceExplanation;
// Don't copy mGlobalSortKey, recompute it.
@@ -274,8 +274,8 @@
pw.println(prefix + " mRecentlyIntrusive=" + mRecentlyIntrusive);
pw.println(prefix + " mPackagePriority=" + mPackagePriority);
pw.println(prefix + " mPackageVisibility=" + mPackageVisibility);
- pw.println(prefix + " mTopicImportance="
- + NotificationListenerService.Ranking.importanceToString(mTopicImportance));
+ pw.println(prefix + " mUserImportance="
+ + NotificationListenerService.Ranking.importanceToString(mUserImportance));
pw.println(prefix + " mImportance="
+ NotificationListenerService.Ranking.importanceToString(mImportance));
pw.println(prefix + " mImportanceExplanation=" + mImportanceExplanation);
@@ -356,17 +356,17 @@
return mPackageVisibility;
}
- public void setTopicImportance(int importance) {
- mTopicImportance = importance;
- applyTopicImportance();
+ public void setUserImportance(int importance) {
+ mUserImportance = importance;
+ applyUserImportance();
}
- private String getTopicExplanation() {
- if (mTopicExplanation == null) {
- mTopicExplanation =
- mContext.getString(com.android.internal.R.string.importance_from_topic);
+ private String getUserExplanation() {
+ if (mUserExplanation == null) {
+ mUserExplanation =
+ mContext.getString(com.android.internal.R.string.importance_from_user);
}
- return mTopicExplanation;
+ return mUserExplanation;
}
private String getPeopleExplanation() {
@@ -377,15 +377,15 @@
return mPeopleExplanation;
}
- private void applyTopicImportance() {
- if (mTopicImportance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
- mImportance = mTopicImportance;
- mImportanceExplanation = getTopicExplanation();
+ private void applyUserImportance() {
+ if (mUserImportance != NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED) {
+ mImportance = mUserImportance;
+ mImportanceExplanation = getUserExplanation();
}
}
- public int getTopicImportance() {
- return mTopicImportance;
+ public int getUserImportance() {
+ return mUserImportance;
}
public void setImportance(int importance, CharSequence explanation) {
@@ -393,7 +393,7 @@
mImportance = importance;
mImportanceExplanation = explanation;
}
- applyTopicImportance();
+ applyUserImportance();
}
public int getImportance() {
@@ -528,6 +528,6 @@
}
public boolean isImportanceFromUser() {
- return mImportance == mTopicImportance;
+ return mImportance == mUserImportance;
}
}
diff --git a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java b/services/core/java/com/android/server/notification/PriorityExtractor.java
similarity index 84%
rename from services/core/java/com/android/server/notification/TopicPriorityExtractor.java
rename to services/core/java/com/android/server/notification/PriorityExtractor.java
index 1df5c2b..6c76476 100644
--- a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
+++ b/services/core/java/com/android/server/notification/PriorityExtractor.java
@@ -21,7 +21,7 @@
/**
* Determines if the given notification can bypass Do Not Disturb.
*/
-public class TopicPriorityExtractor implements NotificationSignalExtractor {
+public class PriorityExtractor implements NotificationSignalExtractor {
private static final String TAG = "ImportantTopicExtractor";
private static final boolean DBG = false;
@@ -42,9 +42,8 @@
return null;
}
- final int packagePriority = mConfig.getPriority(record.sbn.getPackageName(),
- record.sbn.getUid(), record.sbn.getNotification().getTopic());
- record.setPackagePriority(packagePriority);
+ record.setPackagePriority(
+ mConfig.getPriority(record.sbn.getPackageName(), record.sbn.getUid()));
return null;
}
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 9773474..b5cc2ef 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -15,30 +15,17 @@
*/
package com.android.server.notification;
-import android.app.Notification;
-
-import java.util.List;
-
public interface RankingConfig {
- List<Notification.Topic> getTopics(String packageName, int uid);
+ int getPriority(String packageName, int uid);
- int getPriority(String packageName, int uid, Notification.Topic topic);
+ void setPriority(String packageName, int uid, int priority);
- void setPriority(String packageName, int uid, Notification.Topic topic, int priority);
+ int getVisibilityOverride(String packageName, int uid);
- int getVisibilityOverride(String packageName, int uid, Notification.Topic topic);
+ void setVisibilityOverride(String packageName, int uid, int visibility);
- void setVisibilityOverride(String packageName, int uid, Notification.Topic topic,
- int visibility);
+ void setImportance(String packageName, int uid, int importance);
- void setImportance(String packageName, int uid, Notification.Topic topic, int importance);
-
- int getImportance(String packageName, int uid, Notification.Topic topic);
-
- boolean doesUserUseTopics(String packageName, int uid);
-
- boolean hasBannedTopics(String packageName, int uid);
-
- int getImportance(String packageName, int uid, String topicId);
+ int getImportance(String packageName, int uid);
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 91eab10..fd96a78 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -20,14 +20,11 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
-import com.android.internal.R;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -36,8 +33,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
-import java.util.Map;
public class RankingHelper implements RankingConfig {
private static final String TAG = "RankingHelper";
@@ -47,7 +42,6 @@
private static final String TAG_RANKING = "ranking";
private static final String TAG_PACKAGE = "package";
private static final String ATT_VERSION = "version";
- private static final String TAG_TOPIC = "topic";
private static final String ATT_NAME = "name";
private static final String ATT_UID = "uid";
@@ -141,8 +135,6 @@
if (type == XmlPullParser.START_TAG) {
if (TAG_PACKAGE.equals(tag)) {
int uid = safeInt(parser, ATT_UID, Record.UNKNOWN_UID);
- int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
- int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
String name = parser.getAttributeValue(null, ATT_NAME);
if (!TextUtils.isEmpty(name)) {
@@ -165,16 +157,8 @@
r = getOrCreateRecord(name, uid);
}
r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
- r.priority = priority;
- r.visibility = vis;
-
- // Migrate package level settings to the default topic.
- // Might be overwritten by parseTopics.
- Topic defaultTopic = r.topics.get(Notification.TOPIC_DEFAULT);
- defaultTopic.priority = priority;
- defaultTopic.visibility = vis;
-
- parseTopics(r, parser);
+ r.priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
+ r.visibility = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
}
}
}
@@ -182,42 +166,6 @@
throw new IllegalStateException("Failed to reach END_DOCUMENT");
}
- public void parseTopics(Record r, XmlPullParser parser)
- throws XmlPullParserException, IOException {
- final int innerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (TAG_TOPIC.equals(tagName)) {
- int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
- int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
- int importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
- String id = parser.getAttributeValue(null, ATT_TOPIC_ID);
- CharSequence label = parser.getAttributeValue(null, ATT_TOPIC_LABEL);
-
- if (!TextUtils.isEmpty(id)) {
- Topic topic = new Topic(new Notification.Topic(id, label));
-
- if (priority != DEFAULT_PRIORITY) {
- topic.priority = priority;
- }
- if (vis != DEFAULT_VISIBILITY) {
- topic.visibility = vis;
- }
- if (importance != DEFAULT_IMPORTANCE) {
- topic.importance = importance;
- }
- r.topics.put(id, topic);
- }
- }
- }
- }
-
private static String recordKey(String pkg, int uid) {
return pkg + "|" + uid;
}
@@ -229,7 +177,6 @@
r = new Record();
r.pkg = pkg;
r.uid = uid;
- r.topics.put(Notification.TOPIC_DEFAULT, new Topic(createDefaultTopic()));
mRecords.put(key, r);
}
return r;
@@ -246,46 +193,31 @@
if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) {
continue;
}
- out.startTag(null, TAG_PACKAGE);
- out.attribute(null, ATT_NAME, r.pkg);
- if (r.importance != DEFAULT_IMPORTANCE) {
- out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
- }
- if (r.priority != DEFAULT_PRIORITY) {
- out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
- }
- if (r.visibility != DEFAULT_VISIBILITY) {
- out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
- }
+ final boolean hasNonDefaultSettings = r.importance != DEFAULT_IMPORTANCE
+ || r.priority != DEFAULT_PRIORITY || r.visibility != DEFAULT_VISIBILITY;
+ if (hasNonDefaultSettings) {
+ out.startTag(null, TAG_PACKAGE);
+ out.attribute(null, ATT_NAME, r.pkg);
+ if (r.importance != DEFAULT_IMPORTANCE) {
+ out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
+ }
+ if (r.priority != DEFAULT_PRIORITY) {
+ out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
+ }
+ if (r.visibility != DEFAULT_VISIBILITY) {
+ out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
+ }
- if (!forBackup) {
- out.attribute(null, ATT_UID, Integer.toString(r.uid));
- }
+ if (!forBackup) {
+ out.attribute(null, ATT_UID, Integer.toString(r.uid));
+ }
- writeTopicsXml(out, r);
- out.endTag(null, TAG_PACKAGE);
+ out.endTag(null, TAG_PACKAGE);
+ }
}
out.endTag(null, TAG_RANKING);
}
- public void writeTopicsXml(XmlSerializer out, Record r) throws IOException {
- for (Topic t : r.topics.values()) {
- out.startTag(null, TAG_TOPIC);
- out.attribute(null, ATT_TOPIC_ID, t.topic.getId());
- out.attribute(null, ATT_TOPIC_LABEL, t.topic.getLabel().toString());
- if (t.priority != DEFAULT_PRIORITY) {
- out.attribute(null, ATT_PRIORITY, Integer.toString(t.priority));
- }
- if (t.visibility != DEFAULT_VISIBILITY) {
- out.attribute(null, ATT_VISIBILITY, Integer.toString(t.visibility));
- }
- if (t.importance != DEFAULT_IMPORTANCE) {
- out.attribute(null, ATT_IMPORTANCE, Integer.toString(t.importance));
- }
- out.endTag(null, TAG_TOPIC);
- }
- }
-
private void updateConfig() {
final int N = mSignalExtractors.length;
for (int i = 0; i < N; i++) {
@@ -370,189 +302,62 @@
}
}
- private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
- final String val = parser.getAttributeValue(null, att);
- return tryParseBool(val, defValue);
- }
-
private static boolean tryParseBool(String value, boolean defValue) {
if (TextUtils.isEmpty(value)) return defValue;
return Boolean.valueOf(value);
}
+ /**
+ * Gets priority.
+ */
@Override
- public List<Notification.Topic> getTopics(String packageName, int uid) {
- final Record r = getOrCreateRecord(packageName, uid);
- List<Notification.Topic> topics = new ArrayList<>();
- for (Topic t : r.topics.values()) {
- topics.add(t.topic);
- }
- return topics;
- }
-
- @Override
- public boolean hasBannedTopics(String packageName, int uid) {
- final Record r = getOrCreateRecord(packageName, uid);
- for (Topic t : r.topics.values()) {
- if (t.importance == Ranking.IMPORTANCE_NONE) {
- return true;
- }
- }
- return false;
+ public int getPriority(String packageName, int uid) {
+ return getOrCreateRecord(packageName, uid).priority;
}
/**
- * Gets priority. If a topic is given, returns the priority of that topic. Otherwise, the
- * priority of the app.
+ * Sets priority.
*/
@Override
- public int getPriority(String packageName, int uid, Notification.Topic topic) {
- final Record r = getOrCreateRecord(packageName, uid);
- if (topic == null) {
- return r.priority;
- }
- return getOrCreateTopic(r, topic).priority;
- }
-
- /**
- * Sets priority. If a topic is given, sets the priority of that topic. If not,
- * sets the default priority for all new topics that appear in the future, and resets
- * the priority of all current topics.
- */
- @Override
- public void setPriority(String packageName, int uid, Notification.Topic topic,
- int priority) {
- final Record r = getOrCreateRecord(packageName, uid);
- if (topic == null) {
- r.priority = priority;
- for (Topic t : r.topics.values()) {
- t.priority = priority;
- }
- } else {
- getOrCreateTopic(r, topic).priority = priority;
- }
+ public void setPriority(String packageName, int uid, int priority) {
+ getOrCreateRecord(packageName, uid).priority = priority;
updateConfig();
}
/**
- * Gets visual override. If a topic is given, returns the override of that topic. Otherwise, the
- * override of the app.
+ * Gets visual override.
*/
@Override
- public int getVisibilityOverride(String packageName, int uid, Notification.Topic topic) {
- final Record r = getOrCreateRecord(packageName, uid);
- if (topic == null) {
- return r.visibility;
- }
- return getOrCreateTopic(r, topic).visibility;
+ public int getVisibilityOverride(String packageName, int uid) {
+ return getOrCreateRecord(packageName, uid).visibility;
}
/**
- * Sets visibility override. If a topic is given, sets the override of that topic. If not,
- * sets the default override for all new topics that appear in the future, and resets
- * the override of all current topics.
+ * Sets visibility override.
*/
@Override
- public void setVisibilityOverride(String pkgName, int uid, Notification.Topic topic,
- int visibility) {
- final Record r = getOrCreateRecord(pkgName, uid);
- if (topic == null) {
- r.visibility = visibility;
- for (Topic t : r.topics.values()) {
- t.visibility = visibility;
- }
- } else {
- getOrCreateTopic(r, topic).visibility = visibility;
- }
+ public void setVisibilityOverride(String pkgName, int uid, int visibility) {
+ getOrCreateRecord(pkgName, uid).visibility = visibility;
updateConfig();
}
/**
- * Gets the importance of a topic. Unlike {@link #getImportance(String, int, String)}, does not
- * create package or topic records if they don't exist.
+ * Gets importance.
*/
@Override
- public int getImportance(String packageName, int uid, String topicId) {
- final String key = recordKey(packageName, uid);
- Record r = mRecords.get(key);
- if (r == null) {
- return Ranking.IMPORTANCE_UNSPECIFIED;
- }
- Topic t = r.topics.get(topicId);
- if (t == null) {
- return Ranking.IMPORTANCE_UNSPECIFIED;
- }
- return t.importance;
+ public int getImportance(String packageName, int uid) {
+ return getOrCreateRecord(packageName, uid).importance;
}
/**
- * Gets importance. If a topic is given, returns the importance of that topic. Otherwise, the
- * importance of the app.
+ * Sets importance.
*/
@Override
- public int getImportance(String packageName, int uid, Notification.Topic topic) {
- final Record r = getOrCreateRecord(packageName, uid);
- if (topic == null) {
- return r.importance;
- }
- return getOrCreateTopic(r, topic).importance;
- }
-
- /**
- * Sets importance. If a topic is given, sets the importance of that topic. If not, sets the
- * default importance for all new topics that appear in the future, and resets
- * the importance of all current topics (unless the app is being blocked).
- */
- @Override
- public void setImportance(String pkgName, int uid, Notification.Topic topic,
- int importance) {
- final Record r = getOrCreateRecord(pkgName, uid);
- if (topic == null) {
- r.importance = importance;
- if (Ranking.IMPORTANCE_NONE != importance) {
- for (Topic t : r.topics.values()) {
- t.importance = importance;
- }
- }
- } else {
- getOrCreateTopic(r, topic).importance = importance;
- }
+ public void setImportance(String pkgName, int uid, int importance) {
+ getOrCreateRecord(pkgName, uid).importance = importance;
updateConfig();
}
- @Override
- public boolean doesUserUseTopics(String pkgName, int uid) {
- final Record r = getOrCreateRecord(pkgName, uid);
- for (Topic topic : r.topics.values()) {
- if (topic.importance != Ranking.IMPORTANCE_UNSPECIFIED
- && r.importance != topic.importance)
- return true;
- }
- return false;
- }
-
- private Topic getOrCreateTopic(Record r, Notification.Topic topic) {
- if (topic == null) {
- topic = createDefaultTopic();
- }
- Topic t = r.topics.get(topic.getId());
- if (t != null) {
- return t;
- } else {
- t = new Topic(topic);
- t.importance = r.importance;
- t.priority = r.priority;
- t.visibility = r.visibility;
- r.topics.put(topic.getId(), t);
- return t;
- }
- }
-
- private Notification.Topic createDefaultTopic() {
- return new Notification.Topic(Notification.TOPIC_DEFAULT,
- mContext.getString(R.string.default_notification_topic_label));
- }
-
public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
if (filter == null) {
final int N = mSignalExtractors.length;
@@ -600,25 +405,6 @@
pw.print(Ranking.importanceToString(r.visibility));
}
pw.println();
- for (Topic t : r.topics.values()) {
- pw.print(prefix);
- pw.print(" ");
- pw.print(" ");
- pw.print(t.topic.getId());
- if (t.priority != DEFAULT_PRIORITY) {
- pw.print(" priority=");
- pw.print(Notification.priorityToString(t.priority));
- }
- if (t.visibility != DEFAULT_VISIBILITY) {
- pw.print(" visibility=");
- pw.print(Notification.visibilityToString(t.visibility));
- }
- if (t.importance != DEFAULT_IMPORTANCE) {
- pw.print(" importance=");
- pw.print(Ranking.importanceToString(t.importance));
- }
- pw.println();
- }
}
}
}
@@ -657,17 +443,5 @@
int importance = DEFAULT_IMPORTANCE;
int priority = DEFAULT_PRIORITY;
int visibility = DEFAULT_VISIBILITY;
- Map<String, Topic> topics = new ArrayMap<>();
}
-
- private static class Topic {
- Notification.Topic topic;
- int priority = DEFAULT_PRIORITY;
- int visibility = DEFAULT_VISIBILITY;
- int importance = DEFAULT_IMPORTANCE;
-
- public Topic(Notification.Topic topic) {
- this.topic = topic;
- }
- }
}
diff --git a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java b/services/core/java/com/android/server/notification/VisibilityExtractor.java
similarity index 79%
rename from services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
rename to services/core/java/com/android/server/notification/VisibilityExtractor.java
index eaa3ed3..2da2b2f 100644
--- a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/VisibilityExtractor.java
@@ -21,8 +21,8 @@
/**
* Determines if the given notification can display sensitive content on the lockscreen.
*/
-public class TopicVisibilityExtractor implements NotificationSignalExtractor {
- private static final String TAG = "TopicVisibilityExtractor";
+public class VisibilityExtractor implements NotificationSignalExtractor {
+ private static final String TAG = "VisibilityExtractor";
private static final boolean DBG = false;
private RankingConfig mConfig;
@@ -42,10 +42,8 @@
return null;
}
- final int packageVisibility = mConfig.getVisibilityOverride(
- record.sbn.getPackageName(), record.sbn.getUid(),
- record.sbn.getNotification().getTopic());
- record.setPackageVisibilityOverride(packageVisibility);
+ record.setPackageVisibilityOverride(
+ mConfig.getVisibilityOverride(record.sbn.getPackageName(), record.sbn.getUid()));
return null;
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 63c9408..e7c2f6f 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -124,7 +124,6 @@
private final PackageManagerService mService;
- private PackagesProvider mImePackagesProvider;
private PackagesProvider mLocationPackagesProvider;
private PackagesProvider mVoiceInteractionPackagesProvider;
private PackagesProvider mSmsAppPackagesProvider;
@@ -136,10 +135,6 @@
mService = service;
}
- public void setImePackagesProviderLPr(PackagesProvider provider) {
- mImePackagesProvider = provider;
- }
-
public void setLocationPackagesProviderLPw(PackagesProvider provider) {
mLocationPackagesProvider = provider;
}
@@ -198,7 +193,6 @@
private void grantDefaultSystemHandlerPermissions(int userId) {
Log.i(TAG, "Granting permissions to default platform handlers for user " + userId);
- final PackagesProvider imePackagesProvider;
final PackagesProvider locationPackagesProvider;
final PackagesProvider voiceInteractionPackagesProvider;
final PackagesProvider smsAppPackagesProvider;
@@ -207,7 +201,6 @@
final SyncAdapterPackagesProvider syncAdapterPackagesProvider;
synchronized (mService.mPackages) {
- imePackagesProvider = mImePackagesProvider;
locationPackagesProvider = mLocationPackagesProvider;
voiceInteractionPackagesProvider = mVoiceInteractionPackagesProvider;
smsAppPackagesProvider = mSmsAppPackagesProvider;
@@ -216,8 +209,6 @@
syncAdapterPackagesProvider = mSyncAdapterPackagesProvider;
}
- String[] imePackageNames = (imePackagesProvider != null)
- ? imePackagesProvider.getPackages(userId) : null;
String[] voiceInteractPackageNames = (voiceInteractionPackagesProvider != null)
? voiceInteractionPackagesProvider.getPackages(userId) : null;
String[] locationPackageNames = (locationPackagesProvider != null)
@@ -500,17 +491,6 @@
grantRuntimePermissionsLPw(browserPackage, LOCATION_PERMISSIONS, userId);
}
- // IME
- if (imePackageNames != null) {
- for (String imePackageName : imePackageNames) {
- PackageParser.Package imePackage = getSystemPackageLPr(imePackageName);
- if (imePackage != null
- && doesPackageSupportRuntimePermissions(imePackage)) {
- grantRuntimePermissionsLPw(imePackage, CONTACTS_PERMISSIONS, userId);
- }
- }
- }
-
// Voice interaction
if (voiceInteractPackageNames != null) {
for (String voiceInteractPackageName : voiceInteractPackageNames) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cc5b80e..abbad21 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3340,11 +3340,6 @@
+ " with flags 0x" + Integer.toHexString(flags), new Throwable());
}
- // Safe mode means we shouldn't match any third-party components
- if (mSafeMode) {
- flags |= PackageManager.MATCH_SYSTEM_ONLY;
- }
-
return updateFlags(flags, userId);
}
@@ -3352,6 +3347,11 @@
* Update given flags when being used to request {@link ResolveInfo}.
*/
int updateFlagsForResolve(int flags, int userId, Object cookie) {
+ // Safe mode means we shouldn't match any third-party components
+ if (mSafeMode) {
+ flags |= PackageManager.MATCH_SYSTEM_ONLY;
+ }
+
return updateFlagsForComponent(flags, userId, cookie);
}
@@ -18012,6 +18012,7 @@
final PackageSetting ps;
synchronized (mPackages) {
ps = mSettings.mPackages.get(pkg.packageName);
+ mSettings.writeKernelMappingLPr(ps);
}
final UserManager um = mContext.getSystemService(UserManager.class);
@@ -18882,13 +18883,6 @@
}
@Override
- public void setImePackagesProvider(PackagesProvider provider) {
- synchronized (mPackages) {
- mDefaultPermissionPolicy.setImePackagesProviderLPr(provider);
- }
- }
-
- @Override
public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
synchronized (mPackages) {
mDefaultPermissionPolicy.setVoiceInteractionPackagesProviderLPw(provider);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1872371..690cb98 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -19,22 +19,16 @@
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
-import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
-import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
-import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
-import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
-import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE;
-import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE;
-import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
+
import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION;
import android.annotation.NonNull;
@@ -88,7 +82,6 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.JournaledFile;
-import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.PackageManagerService.DumpState;
@@ -170,6 +163,7 @@
private static final boolean DEBUG_STOPPED = false;
private static final boolean DEBUG_MU = false;
+ private static final boolean DEBUG_KERNEL = false;
private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";
@@ -246,9 +240,13 @@
private final File mPackageListFilename;
private final File mStoppedPackagesFilename;
private final File mBackupStoppedPackagesFilename;
+ private final File mKernelMappingFilename;
- final ArrayMap<String, PackageSetting> mPackages =
- new ArrayMap<String, PackageSetting>();
+ /** Map from package name to settings */
+ final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
+
+ /** Map from package name to appId */
+ private final ArrayMap<String, Integer> mKernelMapping = new ArrayMap<>();
// List of replaced system applications
private final ArrayMap<String, PackageSetting> mDisabledSysPackages =
@@ -408,6 +406,9 @@
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
+ final File kernelDir = new File("/config/sdcardfs");
+ mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
+
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
@@ -2342,6 +2343,7 @@
|FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-1, -1);
+ writeKernelMappingLPr();
writePackageListLPr();
writeAllUsersPackageRestrictionsLPr();
writeAllRuntimePermissionsLPr();
@@ -2364,6 +2366,56 @@
//Debug.stopMethodTracing();
}
+ void writeKernelMappingLPr() {
+ if (mKernelMappingFilename == null) return;
+
+ final String[] known = mKernelMappingFilename.list();
+ final ArraySet<String> knownSet = new ArraySet<>(known.length);
+ for (String name : known) {
+ knownSet.add(name);
+ }
+
+ for (final PackageSetting ps : mPackages.values()) {
+ // Package is actively claimed
+ knownSet.remove(ps.name);
+ writeKernelMappingLPr(ps);
+ }
+
+ // Remove any unclaimed mappings
+ for (int i = 0; i < knownSet.size(); i++) {
+ final String name = knownSet.valueAt(i);
+ if (DEBUG_KERNEL) Slog.d(TAG, "Dropping mapping " + name);
+
+ mKernelMapping.remove(name);
+
+ final File dir = new File(mKernelMappingFilename, name);
+ FileUtils.deleteContents(dir);
+ dir.delete();
+ }
+ }
+
+ void writeKernelMappingLPr(PackageSetting ps) {
+ if (mKernelMappingFilename == null) return;
+
+ final Integer cur = mKernelMapping.get(ps.name);
+ if (cur != null && cur.intValue() == ps.appId) {
+ // Ignore when mapping already matches
+ return;
+ }
+
+ if (DEBUG_KERNEL) Slog.d(TAG, "Mapping " + ps.name + " to " + ps.appId);
+
+ final File dir = new File(mKernelMappingFilename, ps.name);
+ dir.mkdir();
+
+ final File file = new File(dir, "appid");
+ try {
+ FileUtils.stringToFile(file, Integer.toString(ps.appId));
+ mKernelMapping.put(ps.name, ps.appId);
+ } catch (IOException ignored) {
+ }
+ }
+
void writePackageListLPr() {
writePackageListLPr(-1);
}
@@ -2395,7 +2447,9 @@
for (final PackageSetting pkg : mPackages.values()) {
if (pkg.pkg == null || pkg.pkg.applicationInfo == null
|| pkg.pkg.applicationInfo.dataDir == null) {
- Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
+ if (!"android".equals(pkg.name)) {
+ Slog.w(TAG, "Skipping " + pkg + " due to missing metadata");
+ }
continue;
}
@@ -2908,6 +2962,8 @@
mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
+ mSharedUsers.size() + " shared uids\n");
+ writeKernelMappingLPr();
+
return true;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 117c663..d5ed04a 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -41,6 +41,7 @@
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.IBinder;
import android.os.IUserManager;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -188,6 +189,8 @@
private final File mUsersDir;
private final File mUserListFile;
+ private static final IBinder mUserRestriconToken = new Binder();
+
/**
* User-related information that is used for persisting to flash. Only UserInfo is
* directly exposed to other system apps.
@@ -840,7 +843,7 @@
/**
* See {@link UserManagerInternal#setDevicePolicyUserRestrictions(int, Bundle, Bundle)}
*/
- void setDevicePolicyUserRestrictions(int userId, @NonNull Bundle local,
+ void setDevicePolicyUserRestrictionsInner(int userId, @NonNull Bundle local,
@Nullable Bundle global) {
Preconditions.checkNotNull(local);
boolean globalChanged = false;
@@ -1016,7 +1019,7 @@
if (mAppOpsService != null) { // We skip it until system-ready.
final long token = Binder.clearCallingIdentity();
try {
- mAppOpsService.setUserRestrictions(effective, userId);
+ mAppOpsService.setUserRestrictions(effective, mUserRestriconToken, userId);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
} finally {
@@ -1833,6 +1836,11 @@
return null;
}
}
+ if (!UserManager.isSplitSystemUser() && (flags & UserInfo.FLAG_EPHEMERAL) != 0) {
+ Log.e(LOG_TAG,
+ "Ephemeral users are supported on split-system-user systems only.");
+ return null;
+ }
// In split system user mode, we assign the first human user the primary flag.
// And if there is no device owner, we also assign the admin flag to primary user.
if (UserManager.isSplitSystemUser()
@@ -2854,7 +2862,7 @@
@Override
public void setDevicePolicyUserRestrictions(int userId, @NonNull Bundle localRestrictions,
@Nullable Bundle globalRestrictions) {
- UserManagerService.this.setDevicePolicyUserRestrictions(userId, localRestrictions,
+ UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, localRestrictions,
globalRestrictions);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e88b72f..716b96f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -33,6 +33,7 @@
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManager.StackId;
import android.app.ActivityManagerInternal;
@@ -2035,7 +2036,7 @@
permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
}
if (permission != null) {
- if (permission == android.Manifest.permission.SYSTEM_ALERT_WINDOW) {
+ if (android.Manifest.permission.SYSTEM_ALERT_WINDOW.equals(permission)) {
final int callingUid = Binder.getCallingUid();
// system processes will be automatically allowed privilege to draw
if (callingUid == Process.SYSTEM_UID) {
@@ -6075,9 +6076,20 @@
public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
Rect outInsets) {
outInsets.setEmpty();
+
+ // Navigation bar and status bar.
+ getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, outInsets);
if (mStatusBar != null) {
outInsets.top = mStatusBarHeight;
}
+ }
+
+ @Override
+ public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
+ Rect outInsets) {
+ outInsets.setEmpty();
+
+ // Only navigation bar
if (mNavigationBar != null) {
if (isNavigationBarOnBottom(displayWidth, displayHeight)) {
outInsets.bottom = getNavigationBarHeight(displayRotation, mUiMode);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a1f24f7..dbaa598 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -49,6 +49,7 @@
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.service.dreams.DreamManagerInternal;
import android.util.EventLog;
import android.util.Slog;
@@ -468,6 +469,9 @@
private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
= new ArrayList<PowerManagerInternal.LowPowerModeListener>();
+ // True if brightness should be affected by twilight.
+ private boolean mBrightnessUseTwilight;
+
private native void nativeInit();
private static native void nativeAcquireSuspendBlocker(String name);
@@ -620,6 +624,9 @@
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DOUBLE_TAP_TO_WAKE),
false, mSettingsObserver, UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Secure.BRIGHTNESS_USE_TWILIGHT),
+ false, mSettingsObserver, UserHandle.USER_ALL);
// Go.
readConfigurationLocked();
updateSettingsLocked();
@@ -726,6 +733,9 @@
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
+ mBrightnessUseTwilight = Settings.Secure.getIntForUser(resolver,
+ Secure.BRIGHTNESS_USE_TWILIGHT, 0, UserHandle.USER_CURRENT) != 0;
+
final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE, 0) != 0;
final boolean autoLowPowerModeConfigured = Settings.Global.getInt(resolver,
@@ -1997,6 +2007,7 @@
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
mDisplayPowerRequest.boostScreenBrightness = mScreenBrightnessBoostInProgress;
+ mDisplayPowerRequest.useTwilight = mBrightnessUseTwilight;
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
diff --git a/services/core/java/com/android/server/twilight/TwilightManager.java b/services/core/java/com/android/server/twilight/TwilightManager.java
index b3de58b..56137a4 100644
--- a/services/core/java/com/android/server/twilight/TwilightManager.java
+++ b/services/core/java/com/android/server/twilight/TwilightManager.java
@@ -20,5 +20,6 @@
public interface TwilightManager {
void registerListener(TwilightListener listener, Handler handler);
+ void unregisterListener(TwilightListener listener);
TwilightState getCurrentState();
}
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index a71961c..ac1ab64 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -19,12 +19,15 @@
import com.android.server.SystemService;
import com.android.server.TwilightCalculator;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
@@ -33,6 +36,9 @@
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Slog;
@@ -54,6 +60,26 @@
static final String ACTION_UPDATE_TWILIGHT_STATE =
"com.android.server.action.UPDATE_TWILIGHT_STATE";
+ // The amount of time after or before sunrise over which to start adjusting
+ // twilight affected things. We want the change to happen gradually so that
+ // it is below the threshold of perceptibility and so that the adjustment has
+ // maximum effect well after dusk.
+ private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
+
+ // Broadcast when twilight changes.
+ public static final String ACTION_TWILIGHT_CHANGED = "android.intent.action.TWILIGHT_CHANGED";
+
+ public static final String EXTRA_IS_NIGHT = "isNight";
+ public static final String EXTRA_AMOUNT = "amount";
+
+ // Amount of time the TwilightService will stay locked in an override state before switching
+ // back to auto.
+ private static final long RESET_TIME = DateUtils.HOUR_IN_MILLIS * 2;
+ private static final String EXTRA_RESET_USER = "user";
+
+ private static final String ACTION_RESET_TWILIGHT_AUTO =
+ "com.android.server.action.RESET_TWILIGHT_AUTO";
+
final Object mLock = new Object();
AlarmManager mAlarmManager;
@@ -65,6 +91,10 @@
TwilightState mTwilightState;
+ private int mCurrentUser;
+ private boolean mLocked;
+ private boolean mBootCompleted;
+
public TwilightService(Context context) {
super(context);
}
@@ -75,14 +105,93 @@
mLocationManager = (LocationManager) getContext().getSystemService(
Context.LOCATION_SERVICE);
mLocationHandler = new LocationHandler();
+ mCurrentUser = ActivityManager.getCurrentUser();
IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
- getContext().registerReceiver(mUpdateLocationReceiver, filter);
+ getContext().registerReceiver(mReceiver, filter);
publishLocalService(TwilightManager.class, mService);
+ getContext().getContentResolver().registerContentObserver(
+ Secure.getUriFor(Secure.TWILIGHT_MODE), false, mContentObserver, mCurrentUser);
+ mContentObserver.onChange(true);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_BOOT_COMPLETED) {
+ mBootCompleted = true;
+ sendBroadcast();
+ }
+ }
+
+ private void reregisterSettingObserver() {
+ final ContentResolver contentResolver = getContext().getContentResolver();
+ contentResolver.unregisterContentObserver(mContentObserver);
+ contentResolver.registerContentObserver(Secure.getUriFor(Secure.TWILIGHT_MODE), false,
+ mContentObserver, mCurrentUser);
+ mContentObserver.onChange(true);
+ }
+
+ private void setLockedState(TwilightState state) {
+ synchronized (mLock) {
+ // Make sure we aren't locked so we can set the state.
+ mLocked = false;
+ setTwilightState(state);
+ // Make sure we leave the state locked, so it cant be changed.
+ mLocked = true;
+ // TODO: Don't bother updating state when locked.
+ }
+ }
+
+ private void setTwilightState(TwilightState state) {
+ synchronized (mLock) {
+ if (mLocked) {
+ // State has been locked by secure setting, shouldn't be changed.
+ return;
+ }
+ if (!Objects.equal(mTwilightState, state)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Twilight state changed: " + state);
+ }
+
+ mTwilightState = state;
+
+ final int listenerLen = mListeners.size();
+ for (int i = 0; i < listenerLen; i++) {
+ mListeners.get(i).postUpdate();
+ }
+ }
+ }
+ sendBroadcast();
+ }
+
+ private void sendBroadcast() {
+ synchronized (mLock) {
+ if (mTwilightState == null) {
+ return;
+ }
+ if (mBootCompleted) {
+ Intent intent = new Intent(ACTION_TWILIGHT_CHANGED);
+ intent.putExtra(EXTRA_IS_NIGHT, mTwilightState.isNight());
+ intent.putExtra(EXTRA_AMOUNT, mTwilightState.getAmount());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ }
+ }
+ }
+
+ private void scheduleReset() {
+ long resetTime = System.currentTimeMillis() + RESET_TIME;
+ Intent resetIntent = new Intent(ACTION_RESET_TWILIGHT_AUTO);
+ resetIntent.putExtra(EXTRA_RESET_USER, mCurrentUser);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ getContext(), 0, resetIntent, 0);
+ mAlarmManager.cancel(pendingIntent);
+ mAlarmManager.setExact(AlarmManager.RTC, resetTime, pendingIntent);
}
private static class TwilightListenerRecord implements Runnable {
@@ -133,24 +242,22 @@
}
}
}
- };
- private void setTwilightState(TwilightState state) {
- synchronized (mLock) {
- if (!Objects.equal(mTwilightState, state)) {
- if (DEBUG) {
- Slog.d(TAG, "Twilight state changed: " + state);
+ @Override
+ public void unregisterListener(TwilightListener listener) {
+ synchronized (mLock) {
+ for (int i = 0; i < mListeners.size(); i++) {
+ if (mListeners.get(i).mListener == listener) {
+ mListeners.remove(i);
+ }
}
- mTwilightState = state;
-
- final int listenerLen = mListeners.size();
- for (int i = 0; i < listenerLen; i++) {
- mListeners.get(i).postUpdate();
+ if (mListeners.size() == 0) {
+ mLocationHandler.disableLocationUpdates();
}
}
}
- }
+ };
// The user has moved if the accuracy circles of the two locations don't overlap.
private static boolean hasMoved(Location from, Location to) {
@@ -183,6 +290,7 @@
private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
private static final int MSG_PROCESS_NEW_LOCATION = 3;
private static final int MSG_DO_TWILIGHT_UPDATE = 4;
+ private static final int MSG_DISABLE_LOCATION_UPDATES = 5;
private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS;
private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
@@ -210,6 +318,10 @@
sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
}
+ public void disableLocationUpdates() {
+ sendEmptyMessage(MSG_DISABLE_LOCATION_UPDATES);
+ }
+
public void requestLocationUpdate() {
sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
}
@@ -311,6 +423,11 @@
}
break;
+ case MSG_DISABLE_LOCATION_UPDATES:
+ mLocationManager.removeUpdates(mLocationListener);
+ removeMessages(MSG_ENABLE_LOCATION_UPDATES);
+ break;
+
case MSG_DO_TWILIGHT_UPDATE:
updateTwilightState();
break;
@@ -368,11 +485,6 @@
final long now = System.currentTimeMillis();
- // calculate yesterday's twilight
- mTwilightCalculator.calculateTwilight(now - DateUtils.DAY_IN_MILLIS,
- mLocation.getLatitude(), mLocation.getLongitude());
- final long yesterdaySunset = mTwilightCalculator.mSunset;
-
// calculate today's twilight
mTwilightCalculator.calculateTwilight(now,
mLocation.getLatitude(), mLocation.getLongitude());
@@ -385,9 +497,19 @@
mLocation.getLatitude(), mLocation.getLongitude());
final long tomorrowSunrise = mTwilightCalculator.mSunrise;
+ float amount = 0;
+ if (isNight) {
+ if (todaySunrise == -1 || todaySunset == -1) {
+ amount = 1;
+ } else if (now > todaySunset) {
+ amount = Math.min(1, (now - todaySunset) / (float) TWILIGHT_ADJUSTMENT_TIME);
+ } else {
+ amount = Math.max(0, 1
+ - (todaySunrise - now) / (float) TWILIGHT_ADJUSTMENT_TIME);
+ }
+ }
// set twilight state
- TwilightState state = new TwilightState(isNight, yesterdaySunset,
- todaySunrise, todaySunset, tomorrowSunrise);
+ TwilightState state = new TwilightState(isNight, amount);
if (DEBUG) {
Slog.d(TAG, "Updating twilight state: " + state);
}
@@ -402,12 +524,18 @@
// add some extra time to be on the safe side.
nextUpdate += DateUtils.MINUTE_IN_MILLIS;
- if (now > todaySunset) {
- nextUpdate += tomorrowSunrise;
- } else if (now > todaySunrise) {
- nextUpdate += todaySunset;
+ if (amount == 1 || amount == 0) {
+ if (now > todaySunset) {
+ nextUpdate += tomorrowSunrise;
+ } else if (now > todaySunrise) {
+ nextUpdate += todaySunset;
+ } else {
+ nextUpdate += todaySunrise;
+ }
} else {
- nextUpdate += todaySunrise;
+ // This is the update rate while transitioning.
+ // Leave at 10 min for now (one from above).
+ nextUpdate += 9 * DateUtils.MINUTE_IN_MILLIS;
}
}
@@ -423,9 +551,37 @@
}
}
- private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
+ private final ContentObserver mContentObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ int value = Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.TWILIGHT_MODE, Secure.TWILIGHT_MODE_LOCKED_OFF, mCurrentUser);
+ if (value == Secure.TWILIGHT_MODE_LOCKED_OFF) {
+ setLockedState(new TwilightState(false, 0));
+ } else if (value == Secure.TWILIGHT_MODE_LOCKED_ON) {
+ setLockedState(new TwilightState(true, 1));
+ } else if (value == Secure.TWILIGHT_MODE_AUTO_OVERRIDE_OFF) {
+ setLockedState(new TwilightState(false, 0));
+ scheduleReset();
+ } else if (value == Secure.TWILIGHT_MODE_AUTO_OVERRIDE_ON) {
+ setLockedState(new TwilightState(true, 1));
+ scheduleReset();
+ } else {
+ mLocked = false;
+ mLocationHandler.requestTwilightUpdate();
+ }
+ }
+ };
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
+ mCurrentUser = ActivityManager.getCurrentUser();
+ reregisterSettingObserver();
+ return;
+ }
if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())
&& !intent.getBooleanExtra("state", false)) {
// Airplane mode is now off!
@@ -433,6 +589,12 @@
return;
}
+ if (ACTION_RESET_TWILIGHT_AUTO.equals(intent.getAction())) {
+ int user = intent.getIntExtra(EXTRA_RESET_USER, 0);
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.TWILIGHT_MODE, Secure.TWILIGHT_MODE_AUTO, user);
+ return;
+ }
// Time zone has changed or alarm expired.
mLocationHandler.requestTwilightUpdate();
}
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
index 91e24d7..81abc13 100644
--- a/services/core/java/com/android/server/twilight/TwilightState.java
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -25,20 +25,11 @@
*/
public class TwilightState {
private final boolean mIsNight;
- private final long mYesterdaySunset;
- private final long mTodaySunrise;
- private final long mTodaySunset;
- private final long mTomorrowSunrise;
+ private final float mAmount;
- TwilightState(boolean isNight,
- long yesterdaySunset,
- long todaySunrise, long todaySunset,
- long tomorrowSunrise) {
+ TwilightState(boolean isNight, float amount) {
mIsNight = isNight;
- mYesterdaySunset = yesterdaySunset;
- mTodaySunrise = todaySunrise;
- mTodaySunset = todaySunset;
- mTomorrowSunrise = tomorrowSunrise;
+ mAmount = amount;
}
/**
@@ -49,35 +40,11 @@
}
/**
- * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
- * or -1 if the sun never sets.
+ * For twilight affects that change gradually over time, this is the amount they
+ * should currently be in effect.
*/
- public long getYesterdaySunset() {
- return mYesterdaySunset;
- }
-
- /**
- * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
- * or -1 if the sun never rises.
- */
- public long getTodaySunrise() {
- return mTodaySunrise;
- }
-
- /**
- * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
- * or -1 if the sun never sets.
- */
- public long getTodaySunset() {
- return mTodaySunset;
- }
-
- /**
- * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
- * or -1 if the sun never rises.
- */
- public long getTomorrowSunrise() {
- return mTomorrowSunrise;
+ public float getAmount() {
+ return mAmount;
}
@Override
@@ -88,10 +55,7 @@
public boolean equals(TwilightState other) {
return other != null
&& mIsNight == other.mIsNight
- && mYesterdaySunset == other.mYesterdaySunset
- && mTodaySunrise == other.mTodaySunrise
- && mTodaySunset == other.mTodaySunset
- && mTomorrowSunrise == other.mTomorrowSunrise;
+ && mAmount == other.mAmount;
}
@Override
@@ -103,10 +67,7 @@
public String toString() {
DateFormat f = DateFormat.getDateTimeInstance();
return "{TwilightState: isNight=" + mIsNight
- + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
- + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
- + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
- + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
+ + ", mAmount=" + mAmount
+ "}";
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 09c53ae..7378bde 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.wallpaper;
+import static android.app.WallpaperManager.FLAG_SET_SYSTEM;
+import static android.app.WallpaperManager.FLAG_SET_LOCK;
import static android.os.ParcelFileDescriptor.*;
import android.app.ActivityManagerNative;
@@ -104,7 +106,7 @@
static final String TAG = "WallpaperManagerService";
static final boolean DEBUG = true;
- final Object mLock = new Object[0];
+ final Object mLock = new Object();
/**
* Minimum time between crashes of a wallpaper service for us to consider
@@ -114,8 +116,17 @@
static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
static final String WALLPAPER = "wallpaper_orig";
static final String WALLPAPER_CROP = "wallpaper";
+ static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
+ static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
static final String WALLPAPER_INFO = "wallpaper_info.xml";
+ // All the various per-user state files we need to be aware of
+ static final String[] sPerUserFiles = new String[] {
+ WALLPAPER, WALLPAPER_CROP,
+ WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP,
+ WALLPAPER_INFO
+ };
+
/**
* Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
* that the wallpaper has changed. The CREATE is triggered when there is no
@@ -124,22 +135,38 @@
*/
private class WallpaperObserver extends FileObserver {
+ final int mUserId;
final WallpaperData mWallpaper;
final File mWallpaperDir;
final File mWallpaperFile;
- final File mWallpaperCropFile;
+ final File mWallpaperLockFile;
final File mWallpaperInfoFile;
public WallpaperObserver(WallpaperData wallpaper) {
super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
CLOSE_WRITE | MOVED_TO | DELETE | DELETE_SELF);
+ mUserId = wallpaper.userId;
mWallpaperDir = getWallpaperDir(wallpaper.userId);
mWallpaper = wallpaper;
mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
- mWallpaperCropFile = new File(mWallpaperDir, WALLPAPER_CROP);
+ mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG);
mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO);
}
+ private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) {
+ WallpaperData wallpaper = null;
+ synchronized (mLock) {
+ if (lockChanged) {
+ wallpaper = mLockWallpaperMap.get(mUserId);
+ }
+ if (wallpaper == null) {
+ // no lock-specific wallpaper exists, or sys case, handled together
+ wallpaper = mWallpaperMap.get(mUserId);
+ }
+ }
+ return (wallpaper != null) ? wallpaper : mWallpaper;
+ }
+
@Override
public void onEvent(int event, String path) {
if (path == null) {
@@ -148,38 +175,77 @@
final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
final File changedFile = new File(mWallpaperDir, path);
+ // System and system+lock changes happen on the system wallpaper input file;
+ // lock-only changes happen on the dedicated lock wallpaper input file
+ final boolean sysWallpaperChanged = (mWallpaperFile.equals(changedFile));
+ final boolean lockWallpaperChanged = (mWallpaperLockFile.equals(changedFile));
+ WallpaperData wallpaper = dataForEvent(sysWallpaperChanged, lockWallpaperChanged);
+
+ if (DEBUG) {
+ Slog.v(TAG, "Wallpaper file change: evt=" + event
+ + " path=" + path
+ + " sys=" + sysWallpaperChanged
+ + " lock=" + lockWallpaperChanged
+ + " imagePending=" + wallpaper.imageWallpaperPending
+ + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending)
+ + " written=" + written);
+ }
synchronized (mLock) {
- if (mWallpaperFile.equals(changedFile)
- || mWallpaperInfoFile.equals(changedFile)) {
+ if (sysWallpaperChanged || mWallpaperInfoFile.equals(changedFile)) {
// changing the wallpaper means we'll need to back up the new one
long origId = Binder.clearCallingIdentity();
BackupManager bm = new BackupManager(mContext);
bm.dataChanged();
Binder.restoreCallingIdentity(origId);
}
- if (mWallpaperFile.equals(changedFile)) {
- notifyCallbacksLocked(mWallpaper);
- if (mWallpaper.wallpaperComponent == null
+ if (sysWallpaperChanged || lockWallpaperChanged) {
+ notifyCallbacksLocked(wallpaper);
+ if (wallpaper.wallpaperComponent == null
|| event != CLOSE_WRITE // includes the MOVED_TO case
- || mWallpaper.imageWallpaperPending) {
+ || wallpaper.imageWallpaperPending) {
if (written) {
// The image source has finished writing the source image,
// so we now produce the crop rect (in the background), and
// only publish the new displayable (sub)image as a result
// of that work.
- generateCrop(mWallpaper);
- mWallpaper.imageWallpaperPending = false;
- if (mWallpaper.setComplete != null) {
+ if (DEBUG) {
+ Slog.v(TAG, "Wallpaper written; generating crop");
+ }
+ generateCrop(wallpaper);
+ if (DEBUG) {
+ Slog.v(TAG, "Crop done; invoking completion callback");
+ }
+ wallpaper.imageWallpaperPending = false;
+ if (wallpaper.setComplete != null) {
try {
- mWallpaper.setComplete.onWallpaperChanged();
+ wallpaper.setComplete.onWallpaperChanged();
} catch (RemoteException e) {
// if this fails we don't really care; the setting app may just
// have crashed and that sort of thing is a fact of life.
}
}
- bindWallpaperComponentLocked(mImageWallpaper, true,
- false, mWallpaper, null);
- saveSettingsLocked(mWallpaper);
+ if (sysWallpaperChanged) {
+ // If this was the system wallpaper, rebind...
+ bindWallpaperComponentLocked(mImageWallpaper, true,
+ false, wallpaper, null);
+ }
+ if (lockWallpaperChanged
+ || (wallpaper.whichPending & FLAG_SET_LOCK) != 0) {
+ // either a lock-only wallpaper commit or a system+lock event,
+ // so tell keyguard about it
+ if (DEBUG) {
+ Slog.i(TAG, "Lock-relevant wallpaper changed; telling listener");
+ }
+ final IWallpaperManagerCallback cb = mKeyguardListener;
+ if (cb != null) {
+ try {
+ cb.onWallpaperChanged();
+ } catch (RemoteException e) {
+ // Oh well it went away; no big deal
+ }
+ }
+ }
+ saveSettingsLocked(wallpaper);
}
}
}
@@ -194,12 +260,21 @@
private void generateCrop(WallpaperData wallpaper) {
boolean success = false;
boolean needCrop = false;
+ boolean needScale = false;
+
+ if (DEBUG) {
+ Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
+ + Integer.toHexString(wallpaper.whichPending)
+ + " to " + wallpaper.cropFile.getName());
+ }
// Analyse the source; needed in multiple cases
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
+ // We'll need to scale if the crop is sufficiently bigger than the display
+
// Legacy case uses an empty crop rect here, so we just preserve the
// source image verbatim
if (!wallpaper.cropHint.isEmpty()) {
@@ -211,7 +286,7 @@
&& options.outWidth >= wallpaper.cropHint.width());
}
- if (!needCrop) {
+ if (!needCrop && !needScale) {
// Simple case: the nominal crop is at least as big as the source image,
// so we take the whole thing and just copy the image file directly.
if (DEBUG) {
@@ -223,7 +298,7 @@
// TODO: fall back to default wallpaper in this case
}
} else {
- // Fancy case: the crop is a subrect of the source
+ // Fancy case: crop and/or scale
FileOutputStream f = null;
BufferedOutputStream bos = null;
try {
@@ -270,6 +345,7 @@
final MyPackageMonitor mMonitor;
final AppOpsManager mAppOpsManager;
WallpaperData mLastWallpaper;
+ IWallpaperManagerCallback mKeyguardListener;
/**
* ID of the current wallpaper, changed every time anything sets a wallpaper.
@@ -283,7 +359,8 @@
*/
final ComponentName mImageWallpaper;
- SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
+ final SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
+ final SparseArray<WallpaperData> mLockWallpaperMap = new SparseArray<WallpaperData>();
int mCurrentUserId;
@@ -291,15 +368,21 @@
int userId;
- final File wallpaperFile;
- final File cropFile;
+ final File wallpaperFile; // source image
+ final File cropFile; // eventual destination
/**
- * Client is currently writing a new image wallpaper.
+ * True while the client is writing a new wallpaper
*/
boolean imageWallpaperPending;
/**
+ * Which new wallpapers are being written; mirrors the 'which'
+ * selector bit field to setWallpaper().
+ */
+ int whichPending;
+
+ /**
* Callback once the set + crop is finished
*/
IWallpaperManagerCallback setComplete;
@@ -345,13 +428,14 @@
final Rect padding = new Rect(0, 0, 0, 0);
- WallpaperData(int userId) {
+ WallpaperData(int userId, String inputFileName, String cropFileName) {
this.userId = userId;
- wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
- cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
+ final File wallpaperDir = getWallpaperDir(userId);
+ wallpaperFile = new File(wallpaperDir, inputFileName);
+ cropFile = new File(wallpaperDir, cropFileName);
}
- // Only called in single-threaded boot sequence mode
+ // Called during initialization of a given user's wallpaper bookkeeping
boolean ensureCropExists() {
// if the crop file is not present, copy over the source image to use verbatim
if (!cropFile.exists()) {
@@ -419,7 +503,7 @@
&& mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME
> SystemClock.uptimeMillis()) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(true, mWallpaper.userId, null);
+ clearWallpaperLocked(true, FLAG_SET_SYSTEM, mWallpaper.userId, null);
} else {
mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
}
@@ -498,7 +582,7 @@
if (!bindWallpaperComponentLocked(comp, false, false,
wallpaper, null)) {
Slog.w(TAG, "Wallpaper no longer available; reverting to default");
- clearWallpaperLocked(false, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
}
}
}
@@ -578,7 +662,7 @@
if (doit) {
Slog.w(TAG, "Wallpaper uninstalled, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
}
}
}
@@ -598,7 +682,7 @@
} catch (NameNotFoundException e) {
Slog.w(TAG, "Wallpaper component gone, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, wallpaper.userId, null);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, null);
}
}
if (wallpaper.nextWallpaperComponent != null
@@ -646,7 +730,7 @@
if (DEBUG) Slog.v(TAG, "systemReady");
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
if (!wallpaper.ensureCropExists()) {
- clearWallpaperLocked(false, UserHandle.USER_SYSTEM, null);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, UserHandle.USER_SYSTEM, null);
}
switchWallpaper(wallpaper, null);
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
@@ -706,37 +790,38 @@
}
}
- void onStoppingUser(int userId) {
- if (userId < 1) return;
- synchronized (mLock) {
- WallpaperData wallpaper = mWallpaperMap.get(userId);
- if (wallpaper != null) {
- if (wallpaper.wallpaperObserver != null) {
- wallpaper.wallpaperObserver.stopWatching();
- wallpaper.wallpaperObserver = null;
- }
- mWallpaperMap.remove(userId);
+ void stopObserver(WallpaperData wallpaper) {
+ if (wallpaper != null) {
+ if (wallpaper.wallpaperObserver != null) {
+ wallpaper.wallpaperObserver.stopWatching();
+ wallpaper.wallpaperObserver = null;
}
}
}
+ void stopObserversLocked(int userId) {
+ stopObserver(mWallpaperMap.get(userId));
+ stopObserver(mLockWallpaperMap.get(userId));
+ mWallpaperMap.remove(userId);
+ mLockWallpaperMap.remove(userId);
+ }
+
void onRemoveUser(int userId) {
if (userId < 1) return;
+
+ final File wallpaperDir = getWallpaperDir(userId);
synchronized (mLock) {
- onStoppingUser(userId);
- File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
- wallpaperFile.delete();
- File cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
- cropFile.delete();
- File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
- wallpaperInfoFile.delete();
+ stopObserversLocked(userId);
+ for (String filename : sPerUserFiles) {
+ new File(wallpaperDir, filename).delete();
+ }
}
}
void switchUser(int userId, IRemoteCallback reply) {
synchronized (mLock) {
mCurrentUserId = userId;
- WallpaperData wallpaper = getWallpaperSafeLocked(userId);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
// Not started watching yet, in case wallpaper data was loaded for other reasons.
if (wallpaper.wallpaperObserver == null) {
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
@@ -759,32 +844,71 @@
e = e1;
}
Slog.w(TAG, "Failure starting previous wallpaper", e);
- clearWallpaperLocked(false, wallpaper.userId, reply);
+ clearWallpaperLocked(false, FLAG_SET_SYSTEM, wallpaper.userId, reply);
}
}
- public void clearWallpaper(String callingPackage) {
+ @Override
+ public void clearWallpaper(String callingPackage, int which, int userId) {
if (DEBUG) Slog.v(TAG, "clearWallpaper");
checkPermission(android.Manifest.permission.SET_WALLPAPER);
if (!isWallpaperSupported(callingPackage) || !isWallpaperSettingAllowed(callingPackage)) {
return;
}
+ if (userId != UserHandle.getCallingUserId()) {
+ // cross-user call
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "WallpaperManagerService");
+ }
+
synchronized (mLock) {
- clearWallpaperLocked(false, UserHandle.getCallingUserId(), null);
+ clearWallpaperLocked(false, which, userId, null);
}
}
- void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) {
- WallpaperData wallpaper = mWallpaperMap.get(userId);
+ void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
+ if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
+ }
+
+ WallpaperData wallpaper = null;
+ if (which == FLAG_SET_LOCK) {
+ wallpaper = mLockWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ // It's already gone; we're done.
+ return;
+ }
+ } else {
+ wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ // Might need to bring it in the first time to establish our rewrite
+ loadSettingsLocked(userId);
+ wallpaper = mWallpaperMap.get(userId);
+ }
+ }
if (wallpaper == null) {
return;
}
- if (wallpaper.wallpaperFile.exists()) {
- wallpaper.wallpaperFile.delete();
- wallpaper.cropFile.delete();
- }
+
final long ident = Binder.clearCallingIdentity();
try {
+ if (wallpaper.wallpaperFile.exists()) {
+ wallpaper.wallpaperFile.delete();
+ wallpaper.cropFile.delete();
+ if (which == FLAG_SET_LOCK) {
+ final IWallpaperManagerCallback cb = mKeyguardListener;
+ if (cb != null) {
+ try {
+ cb.onWallpaperChanged();
+ } catch (RemoteException e) {
+ // Oh well it went away; no big deal
+ }
+ }
+ return;
+ }
+ }
+
RuntimeException e = null;
try {
wallpaper.imageWallpaperPending = false;
@@ -859,7 +983,7 @@
}
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
@@ -921,7 +1045,7 @@
}
synchronized (mLock) {
int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId);
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SET_SYSTEM);
if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
throw new IllegalArgumentException("padding must be positive: " + padding);
}
@@ -948,28 +1072,41 @@
}
}
- public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
- Bundle outParams) {
+ @Override
+ public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, final int which,
+ Bundle outParams, int wallpaperUserId) {
+ if (wallpaperUserId != UserHandle.getCallingUserId()) {
+ // cross-user call
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "WallpaperManagerService");
+ }
+
+ if (which != FLAG_SET_SYSTEM && which != FLAG_SET_LOCK) {
+ throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to read");
+ }
+
synchronized (mLock) {
- // This returns the current user's wallpaper, if called by a system service. Else it
- // returns the wallpaper for the calling user.
- int callingUid = Binder.getCallingUid();
- int wallpaperUserId = 0;
- if (callingUid == android.os.Process.SYSTEM_UID) {
- wallpaperUserId = mCurrentUserId;
- } else {
- wallpaperUserId = UserHandle.getUserId(callingUid);
- }
- WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
+ final SparseArray<WallpaperData> whichSet =
+ (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ WallpaperData wallpaper = whichSet.get(wallpaperUserId);
if (wallpaper == null) {
- return null;
+ // common case, this is the first lookup post-boot of the system or
+ // unified lock, so we bring up the saved state lazily now and recheck.
+ loadSettingsLocked(wallpaperUserId);
+ wallpaper = whichSet.get(wallpaperUserId);
+ if (wallpaper == null) {
+ return null;
+ }
}
try {
if (outParams != null) {
outParams.putInt("width", wallpaper.width);
outParams.putInt("height", wallpaper.height);
}
- wallpaper.callbacks.register(cb);
+ if (cb != null) {
+ wallpaper.callbacks.register(cb);
+ }
if (!wallpaper.cropFile.exists()) {
return null;
}
@@ -994,11 +1131,21 @@
}
@Override
+ public boolean setLockWallpaperCallback(IWallpaperManagerCallback cb) {
+ checkPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW);
+ synchronized (mLock) {
+ mKeyguardListener = cb;
+ }
+ return true;
+ }
+
+ @Override
public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
- if (which == 0) {
+ if ((which & (FLAG_SET_LOCK|FLAG_SET_SYSTEM)) == 0) {
+ Slog.e(TAG, "Must specify a valid wallpaper category to set");
return null;
}
@@ -1017,15 +1164,19 @@
}
}
+ final int userId = UserHandle.getCallingUserId();
+
synchronized (mLock) {
- if (DEBUG) Slog.v(TAG, "setWallpaper");
- int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = getWallpaperSafeLocked(userId);
+ if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
+ WallpaperData wallpaper;
+
+ wallpaper = getWallpaperSafeLocked(userId, which);
final long ident = Binder.clearCallingIdentity();
try {
ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
if (pfd != null) {
wallpaper.imageWallpaperPending = true;
+ wallpaper.whichPending = which;
wallpaper.setComplete = completion;
wallpaper.cropHint.set(cropHint);
}
@@ -1048,10 +1199,9 @@
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
}
- File file = new File(dir, WALLPAPER);
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
- if (!SELinux.restorecon(file)) {
+ if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
return null;
}
wallpaper.name = name;
@@ -1061,7 +1211,7 @@
}
if (DEBUG) {
Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
- + " name=" + name);
+ + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
}
return fd;
} catch (FileNotFoundException e) {
@@ -1417,11 +1567,36 @@
* want to update the data. The data is going to be applied when the user switch observer
* is eventually executed.
*/
- private WallpaperData getWallpaperSafeLocked(int userId) {
- WallpaperData wallpaper = mWallpaperMap.get(userId);
+ private WallpaperData getWallpaperSafeLocked(int userId, int which) {
+ // We're setting either just system (work with the system wallpaper),
+ // both (also work with the system wallpaper), or just the lock
+ // wallpaper (update against the existing lock wallpaper if any).
+ // Combined or just-system operations use the 'system' WallpaperData
+ // for this use; lock-only operations use the dedicated one.
+ final SparseArray<WallpaperData> whichSet =
+ (which == FLAG_SET_LOCK) ? mLockWallpaperMap : mWallpaperMap;
+ WallpaperData wallpaper = whichSet.get(userId);
if (wallpaper == null) {
+ // common case, this is the first lookup post-boot of the system or
+ // unified lock, so we bring up the saved state lazily now and recheck.
loadSettingsLocked(userId);
- wallpaper = mWallpaperMap.get(userId);
+ wallpaper = whichSet.get(userId);
+ // if it's still null here, this is a lock-only operation and there is not
+ // yet a lock-only wallpaper set for this user, so we need to establish
+ // it now.
+ if (wallpaper == null) {
+ if (which == FLAG_SET_LOCK) {
+ wallpaper = new WallpaperData(userId,
+ WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ mLockWallpaperMap.put(userId, wallpaper);
+ } else {
+ // sanity fallback: we're in bad shape, but establishing a known
+ // valid system+lock WallpaperData will keep us from dying.
+ Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
+ wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
+ mWallpaperMap.put(userId, wallpaper);
+ }
+ }
}
return wallpaper;
}
@@ -1438,8 +1613,9 @@
}
WallpaperData wallpaper = mWallpaperMap.get(userId);
if (wallpaper == null) {
- wallpaper = new WallpaperData(userId);
+ wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
mWallpaperMap.put(userId, wallpaper);
+ wallpaper.ensureCropExists();
}
boolean success = false;
try {
@@ -1453,28 +1629,10 @@
if (type == XmlPullParser.START_TAG) {
String tag = parser.getName();
if ("wp".equals(tag)) {
- final String idString = parser.getAttributeValue(null, "id");
- if (idString != null) {
- final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
- if (id > mWallpaperId) {
- mWallpaperId = id;
- }
- } else {
- wallpaper.wallpaperId = makeWallpaperIdLocked();
- }
+ // Common to system + lock wallpapers
+ parseWallpaperAttributes(parser, wallpaper);
- wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
- wallpaper.height = Integer.parseInt(parser
- .getAttributeValue(null, "height"));
- wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
- wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
- wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
- wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
- wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
- wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
- wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
- wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
- wallpaper.name = parser.getAttributeValue(null, "name");
+ // A system wallpaper might also be a live wallpaper
String comp = parser.getAttributeValue(null, "component");
wallpaper.nextWallpaperComponent = comp != null
? ComponentName.unflattenFromString(comp)
@@ -1493,6 +1651,15 @@
Slog.v(TAG, "mNextWallpaperComponent:"
+ wallpaper.nextWallpaperComponent);
}
+ } else if ("kwp".equals(tag)) {
+ // keyguard-specific wallpaper for this user
+ WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
+ if (lockWallpaper == null) {
+ lockWallpaper = new WallpaperData(userId,
+ WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ mLockWallpaperMap.put(userId, lockWallpaper);
+ }
+ parseWallpaperAttributes(parser, lockWallpaper);
}
}
} while (type != XmlPullParser.END_DOCUMENT);
@@ -1543,6 +1710,31 @@
}
}
+ private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper) {
+ final String idString = parser.getAttributeValue(null, "id");
+ if (idString != null) {
+ final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
+ if (id > mWallpaperId) {
+ mWallpaperId = id;
+ }
+ } else {
+ wallpaper.wallpaperId = makeWallpaperIdLocked();
+ }
+
+ wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
+ wallpaper.height = Integer.parseInt(parser
+ .getAttributeValue(null, "height"));
+ wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
+ wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
+ wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
+ wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
+ wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
+ wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
+ wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
+ wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
+ wallpaper.name = parser.getAttributeValue(null, "name");
+ }
+
private int getMaximumSizeDimension() {
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index e6b649e7..2c15818 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -60,6 +60,7 @@
import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -1019,9 +1020,17 @@
boolean focusedWindowAdded = false;
final int visibleWindowCount = visibleWindows.size();
+ int skipRemainingWindowsForTaskId = -1;
+ HashSet<Integer> skipRemainingWindowsForTasks = new HashSet<>();
for (int i = visibleWindowCount - 1; i >= 0; i--) {
final WindowState windowState = visibleWindows.valueAt(i);
final int flags = windowState.mAttrs.flags;
+ final Task task = windowState.getTask();
+
+ // If the window is part of a task that we're finished with - ignore.
+ if (task != null && skipRemainingWindowsForTasks.contains(task.mTaskId)) {
+ continue;
+ }
// If the window is not touchable - ignore.
if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
@@ -1062,10 +1071,19 @@
break;
}
- // If a window is modal, no other below can be touched - done.
+ // If a window is modal it prevents other windows from being touched
if ((flags & (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)) == 0) {
- break;
+ if (task != null) {
+ // If the window is associated with a particular task, we can skip the
+ // rest of the windows for that task.
+ skipRemainingWindowsForTasks.add(task.mTaskId);
+ continue;
+ } else {
+ // If the window is not associated with a particular task, then it is
+ // globally modal. In this case we can skip all remaining windows.
+ break;
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 1821487..5cb7099 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -46,13 +46,13 @@
import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.view.AppTransitionAnimationSpec;
@@ -63,8 +63,6 @@
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.ClipRectAnimation;
-import android.view.animation.ClipRectLRAnimation;
-import android.view.animation.ClipRectTBAnimation;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.view.animation.ScaleAnimation;
@@ -73,10 +71,11 @@
import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache;
import com.android.server.wm.WindowManagerService.H;
+import com.android.server.wm.animation.ClipRectLRAnimation;
+import com.android.server.wm.animation.ClipRectTBAnimation;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -135,6 +134,16 @@
private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+
+ /** Interpolator to be used for animations that respond directly to a touch */
+ static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
+ new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
+ /**
+ * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
+ * involved, to make it more understandable.
+ */
+ private static final int MAX_CLIP_REVEAL_TRANSITION_DURATION = 420;
private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
@@ -199,17 +208,17 @@
private final Interpolator mFastOutLinearInInterpolator;
private final Interpolator mClipHorizontalInterpolator = new PathInterpolator(0, 0, 0.4f, 1f);
- /** Interpolator to be used for animations that respond directly to a touch */
- private final Interpolator mTouchResponseInterpolator =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
-
private final int mClipRevealTranslationY;
private int mCurrentUserId = 0;
+ private long mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
+ private int mLastClipRevealMaxTranslation;
+ private boolean mLastHadClipReveal;
+
AppTransition(Context context, WindowManagerService service) {
mContext = context;
mService = service;
@@ -331,19 +340,25 @@
if (!isRunning()) {
mAppTransitionState = APP_STATE_IDLE;
notifyAppTransitionPendingLocked();
+ mLastHadClipReveal = false;
+ mLastClipRevealMaxTranslation = 0;
+ mLastClipRevealTransitionDuration = DEFAULT_APP_TRANSITION_DURATION;
return true;
}
return false;
}
- void goodToGo(AppWindowAnimator openingAppAnimator, AppWindowAnimator closingAppAnimator) {
+ void goodToGo(AppWindowAnimator topOpeningAppAnimator, AppWindowAnimator topClosingAppAnimator,
+ ArraySet<AppWindowToken> openingApps, ArraySet<AppWindowToken> closingApps) {
mNextAppTransition = TRANSIT_UNSET;
mAppTransitionState = APP_STATE_RUNNING;
notifyAppTransitionStartingLocked(
- openingAppAnimator != null ? openingAppAnimator.mAppToken.token : null,
- closingAppAnimator != null ? closingAppAnimator.mAppToken.token : null,
- openingAppAnimator != null ? openingAppAnimator.animation : null,
- closingAppAnimator != null ? closingAppAnimator.animation : null);
+ topOpeningAppAnimator != null ? topOpeningAppAnimator.mAppToken.token : null,
+ topClosingAppAnimator != null ? topClosingAppAnimator.mAppToken.token : null,
+ topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null,
+ topClosingAppAnimator != null ? topClosingAppAnimator.animation : null);
+ mService.getDefaultDisplayContentLocked().getDockedDividerController()
+ .notifyAppTransitionStarting(openingApps, closingApps);
}
void clear() {
@@ -632,50 +647,118 @@
bitmap, new Rect(left, top, left + width, top + height));
}
- private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame) {
+ /**
+ * @return the duration of the last clip reveal animation
+ */
+ long getLastClipRevealTransitionDuration() {
+ return mLastClipRevealTransitionDuration;
+ }
+
+ /**
+ * @return the maximum distance the app surface is traveling of the last clip reveal animation
+ */
+ int getLastClipRevealMaxTranslation() {
+ return mLastClipRevealMaxTranslation;
+ }
+
+ /**
+ * @return true if in the last app transition had a clip reveal animation, false otherwise
+ */
+ boolean hadClipRevealAnimation() {
+ return mLastHadClipReveal;
+ }
+
+ /**
+ * Calculates the duration for the clip reveal animation. If the clip is "cut off", meaning that
+ * the start rect is outside of the target rect, and there is a lot of movement going on.
+ *
+ * @param cutOff whether the start rect was not fully contained by the end rect
+ * @param translationX the total translation the surface moves in x direction
+ * @param translationY the total translation the surfaces moves in y direction
+ * @param displayFrame our display frame
+ *
+ * @return the duration of the clip reveal animation, in milliseconds
+ */
+ private long calculateClipRevealTransitionDuration(boolean cutOff, float translationX,
+ float translationY, Rect displayFrame) {
+ if (!cutOff) {
+ return DEFAULT_APP_TRANSITION_DURATION;
+ }
+ final float fraction = Math.max(Math.abs(translationX) / displayFrame.width(),
+ Math.abs(translationY) / displayFrame.height());
+ return (long) (DEFAULT_APP_TRANSITION_DURATION + fraction *
+ (MAX_CLIP_REVEAL_TRANSITION_DURATION - DEFAULT_APP_TRANSITION_DURATION));
+ }
+
+ private Animation createClipRevealAnimationLocked(int transit, boolean enter, Rect appFrame,
+ Rect displayFrame) {
final Animation anim;
if (enter) {
- // Reveal will expand and move faster in horizontal direction
-
final int appWidth = appFrame.width();
final int appHeight = appFrame.height();
+
// mTmpRect will contain an area around the launcher icon that was pressed. We will
// clip reveal from that area in the final area of the app.
getDefaultNextAppTransitionStartRect(mTmpRect);
float t = 0f;
if (appHeight > 0) {
- t = (float) mTmpRect.left / appHeight;
+ t = (float) mTmpRect.top / displayFrame.height();
}
- int translationY = mClipRevealTranslationY + (int)(appHeight / 7f * t);
-
+ int translationY = mClipRevealTranslationY + (int)(displayFrame.height() / 7f * t);
+ int translationX = 0;
+ int translationYCorrection = translationY;
int centerX = mTmpRect.centerX();
int centerY = mTmpRect.centerY();
int halfWidth = mTmpRect.width() / 2;
int halfHeight = mTmpRect.height() / 2;
+ int clipStartX = centerX - halfWidth - appFrame.left;
+ int clipStartY = centerY - halfHeight - appFrame.top;
+ boolean cutOff = false;
+
+ // If the starting rectangle is fully or partially outside of the target rectangle, we
+ // need to start the clipping at the edge and then achieve the rest with translation
+ // and extending the clip rect from that edge.
+ if (appFrame.top > centerY - halfHeight) {
+ translationY = (centerY - halfHeight) - appFrame.top;
+ translationYCorrection = 0;
+ clipStartY = 0;
+ cutOff = true;
+ }
+ if (appFrame.left > centerX - halfWidth) {
+ translationX = (centerX - halfWidth) - appFrame.left;
+ clipStartX = 0;
+ cutOff = true;
+ }
+ if (appFrame.right < centerX + halfWidth) {
+ translationX = (centerX + halfWidth) - appFrame.right;
+ clipStartX = appWidth - mTmpRect.width();
+ cutOff = true;
+ }
+ final long duration = calculateClipRevealTransitionDuration(cutOff, translationX,
+ translationY, displayFrame);
// Clip third of the from size of launch icon, expand to full width/height
Animation clipAnimLR = new ClipRectLRAnimation(
- centerX - halfWidth, centerX + halfWidth, 0, appWidth);
+ clipStartX, clipStartX + mTmpRect.width(), 0, appWidth);
clipAnimLR.setInterpolator(mClipHorizontalInterpolator);
- clipAnimLR.setDuration((long) (DEFAULT_APP_TRANSITION_DURATION / 2.5f));
+ clipAnimLR.setDuration((long) (duration / 2.5f));
- Animation clipAnimTB = new ClipRectTBAnimation(centerY - halfHeight - translationY,
- centerY + halfHeight/ 2 - translationY, 0, appHeight);
- clipAnimTB.setInterpolator(mTouchResponseInterpolator);
- clipAnimTB.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ TranslateAnimation translate = new TranslateAnimation(translationX, 0, translationY, 0);
+ translate.setInterpolator(cutOff ? TOUCH_RESPONSE_INTERPOLATOR
+ : mLinearOutSlowInInterpolator);
+ translate.setDuration(duration);
- // We might be animating entrance of a docked task, so we need the translate to account
- // for the app frame in which the window will reside. Every other calculation here
- // is performed as if the window started at 0,0.
- translationY -= appFrame.top;
- TranslateAnimation translate = new TranslateAnimation(-appFrame.left, 0, translationY,
- 0);
- translate.setInterpolator(mLinearOutSlowInInterpolator);
- translate.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ Animation clipAnimTB = new ClipRectTBAnimation(
+ clipStartY, clipStartY + mTmpRect.height(),
+ 0, appHeight,
+ translationYCorrection, 0,
+ mLinearOutSlowInInterpolator);
+ clipAnimTB.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
+ clipAnimTB.setDuration(duration);
// Quick fade-in from icon to app window
- final int alphaDuration = DEFAULT_APP_TRANSITION_DURATION / 4;
+ final long alphaDuration = duration / 4;
AlphaAnimation alpha = new AlphaAnimation(0.5f, 1);
alpha.setDuration(alphaDuration);
alpha.setInterpolator(mLinearOutSlowInInterpolator);
@@ -688,6 +771,13 @@
set.setZAdjustment(Animation.ZORDER_TOP);
set.initialize(appWidth, appHeight, appWidth, appHeight);
anim = set;
+ mLastHadClipReveal = true;
+ mLastClipRevealTransitionDuration = duration;
+
+ // If the start rect was full inside the target rect (cutOff == false), we don't need
+ // to store the translation, because it's only used if cutOff == true.
+ mLastClipRevealMaxTranslation = cutOff
+ ? Math.max(Math.abs(translationY), Math.abs(translationX)) : 0;
} else {
final long duration;
switch (transit) {
@@ -794,7 +884,7 @@
// Animation up from the thumbnail to the full screen
Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
- scale.setInterpolator(mTouchResponseInterpolator);
+ scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(1f, 0f);
alpha.setInterpolator(mThumbnailFadeOutInterpolator);
@@ -802,7 +892,7 @@
final float toX = appRect.left + appRect.width() / 2 -
(mTmpRect.left + thumbWidth / 2);
Animation translate = new TranslateAnimation(0, toX, 0, toY);
- translate.setInterpolator(mTouchResponseInterpolator);
+ translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
// This AnimationSet uses the Interpolators assigned above.
@@ -815,7 +905,7 @@
// Animation down from the full screen to the thumbnail
Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
- scale.setInterpolator(mTouchResponseInterpolator);
+ scale.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
Animation alpha = new AlphaAnimation(0f, 1f);
alpha.setInterpolator(mThumbnailFadeInInterpolator);
@@ -823,7 +913,7 @@
final float toX = appRect.left + appRect.width() / 2 -
(mTmpRect.left + thumbWidth / 2);
Animation translate = new TranslateAnimation(toX, 0, toY, 0);
- translate.setInterpolator(mTouchResponseInterpolator);
+ translate.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
translate.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
// This AnimationSet uses the Interpolators assigned above.
@@ -835,7 +925,7 @@
}
return prepareThumbnailAnimationWithDuration(a, appWidth, appRect.height(), 0,
- mTouchResponseInterpolator);
+ TOUCH_RESPONSE_INTERPOLATOR);
}
/**
@@ -967,7 +1057,7 @@
int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
THUMBNAIL_APP_TRANSITION_DURATION);
return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
- mTouchResponseInterpolator);
+ TOUCH_RESPONSE_INTERPOLATOR);
}
private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
@@ -1219,8 +1309,9 @@
* bigger.
*/
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
- int orientation, Rect frame, Rect insets, @Nullable Rect surfaceInsets,
- boolean isVoiceInteraction, boolean freeform, int taskId) {
+ int orientation, Rect frame, Rect displayFrame, Rect insets,
+ @Nullable Rect surfaceInsets, boolean isVoiceInteraction, boolean freeform,
+ int taskId) {
Animation a;
if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
|| transit == TRANSIT_TASK_OPEN
@@ -1265,7 +1356,7 @@
+ " transit=" + appTransitionToString(transit)
+ " Callers=" + Debug.getCallers(3));
} else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
- a = createClipRevealAnimationLocked(transit, enter, frame);
+ a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
"applyAnimation:"
+ " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 56ae8e0..12c62bd 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -254,7 +254,7 @@
// In cases where there are multiple windows, we prefer the non-exiting window. This
// happens for example when replacing windows during an activity relaunch. When
// constructing the animation, we want the new window, not the exiting one.
- if (win.mExiting) {
+ if (win.mAnimatingExit) {
candidate = win;
} else {
return win;
@@ -307,11 +307,11 @@
// If the app already requested to remove its window, we don't modify
// its exiting state. Otherwise the stale window won't get removed on
// exit and could cause focus to be given to the wrong window.
- if (!(win.mRemoveOnExit && win.mExiting)) {
- win.mExiting = exiting;
+ if (!(win.mRemoveOnExit && win.mAnimatingExit)) {
+ win.mAnimatingExit = exiting;
}
// If we're no longer exiting, remove the window from destroying list
- if (!win.mExiting && win.mDestroying) {
+ if (!win.mAnimatingExit && win.mDestroying) {
win.mDestroying = false;
service.mDestroySurface.remove(win);
}
@@ -330,13 +330,13 @@
continue;
}
- if (!mAppStopped && !win.mClientRemoveRequested) {
+ if (!(mAppStopped || win.mWindowRemovalAllowed)) {
continue;
}
win.destroyOrSaveSurface();
if (win.mRemoveOnExit) {
- win.mExiting = false;
+ win.mAnimatingExit = false;
service.removeWindowInnerLocked(win);
}
final DisplayContent displayContent = win.getDisplayContent();
@@ -393,7 +393,9 @@
int numDrawn = 0;
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
- w.restoreSavedSurface();
+ if (w.hasSavedSurface()) {
+ w.restoreSavedSurface();
+ }
if (w != startingWindow && !w.mAppDied
&& (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
numInteresting++;
@@ -403,7 +405,7 @@
}
}
- allDrawn |= (numInteresting == numDrawn);
+ allDrawn |= (numInteresting > 0) && (numInteresting == numDrawn);
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
"restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 144d7ac..73cea52 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -127,7 +127,7 @@
isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
mService = service;
initializeDisplayBaseInfo();
- mDividerControllerLocked = new DockedStackDividerController(service.mContext, this);
+ mDividerControllerLocked = new DockedStackDividerController(service, this);
mDimLayerController = new DimLayerController(this);
}
@@ -606,12 +606,24 @@
return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
}
+ /**
+ * @return The docked stack, but only if it is visible, and {@code null} otherwise.
+ */
TaskStack getDockedStackLocked() {
final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
return (stack != null && stack.isVisibleLocked()) ? stack : null;
}
/**
+ * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not
+ * visible, as long as it's not hidden because the current user doesn't have any tasks there.
+ */
+ TaskStack getDockedStackVisibleForUserLocked() {
+ final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ return (stack != null && stack.isVisibleForUserLocked()) ? stack : null;
+ }
+
+ /**
* Find the visible, touch-deliverable window under the given point
*/
WindowState getTouchableWinAtPointLocked(float xf, float yf) {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 75c06ff..b6aa3f2 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -20,10 +20,13 @@
import android.graphics.Rect;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.IDockedStackListener;
import android.view.SurfaceControl;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.server.wm.DimLayer.DimLayerUser;
@@ -35,6 +38,8 @@
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
+import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -45,25 +50,65 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
+ /**
+ * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
+ * revealing surface at the earliest.
+ */
+ private static final float CLIP_REVEAL_MEET_EARLIEST = 0.6f;
+
+ /**
+ * The fraction during the maximize/clip reveal animation the divider meets the edge of the clip
+ * revealing surface at the latest.
+ */
+ private static final float CLIP_REVEAL_MEET_LAST = 1f;
+
+ /**
+ * If the app translates at least CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance, we start
+ * meet somewhere between {@link #CLIP_REVEAL_MEET_LAST} and {@link #CLIP_REVEAL_MEET_EARLIEST}.
+ */
+ private static final float CLIP_REVEAL_MEET_FRACTION_MIN = 0.4f;
+
+ /**
+ * If the app translates equals or more than CLIP_REVEAL_MEET_FRACTION_MIN * minimize distance,
+ * we meet at {@link #CLIP_REVEAL_MEET_EARLIEST}.
+ */
+ private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f;
+
+ private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
private final int mDividerWindowWidth;
private final int mDividerInsets;
private boolean mResizing;
private WindowState mWindow;
private final Rect mTmpRect = new Rect();
+ private final Rect mTmpRect2 = new Rect();
private final Rect mLastRect = new Rect();
private boolean mLastVisibility = false;
private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
= new RemoteCallbackList<>();
private final DimLayer mDimLayer;
- DockedStackDividerController(Context context, DisplayContent displayContent) {
+ private boolean mMinimizedDock;
+ private boolean mAnimating;
+ private boolean mAnimationStarted;
+ private long mAnimationStartTime;
+ private float mAnimationStart;
+ private float mAnimationTarget;
+ private long mAnimationDuration;
+ private final Interpolator mMinimizedDockInterpolator;
+ private float mMaximizeMeetFraction;
+
+ DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
+ mService = service;
mDisplayContent = displayContent;
+ final Context context = service.mContext;
mDividerWindowWidth = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
mDividerInsets = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_insets);
mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId());
+ mMinimizedDockInterpolator = AnimationUtils.loadInterpolator(
+ context, android.R.interpolator.fast_out_slow_in);
}
boolean isResizing() {
@@ -180,6 +225,19 @@
mDockedStackListeners.finishBroadcast();
}
+ void notifyDockedStackMinimizedChanged(boolean minimizedDock, long animDuration) {
+ final int size = mDockedStackListeners.beginBroadcast();
+ for (int i = 0; i < size; ++i) {
+ final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+ try {
+ listener.onDockedStackMinimizedChanged(minimizedDock, animDuration);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Error delivering minimized dock changed event.", e);
+ }
+ }
+ mDockedStackListeners.finishBroadcast();
+ }
+
void registerDockedStackListener(IDockedStackListener listener) {
mDockedStackListeners.register(listener);
notifyDockedDividerVisibilityChanged(wasVisible());
@@ -207,6 +265,183 @@
SurfaceControl.closeTransaction();
}
+ /**
+ * Notifies the docked stack divider controller of a visibility change that happens without
+ * an animation.
+ */
+ void notifyAppVisibilityChanged(AppWindowToken wtoken, boolean visible) {
+ final Task task = wtoken.mTask;
+ if (!task.isHomeTask() || !task.isVisibleForUser()) {
+ return;
+ }
+
+ // If the stack is completely offscreen, this might just be an intermediate state when
+ // docking a task/launching recents at the same time, but home doesn't actually get
+ // visible after the state settles in.
+ if (isWithinDisplay(task)
+ && mDisplayContent.getDockedStackVisibleForUserLocked() != null) {
+ setMinimizedDockedStack(visible, false /* animate */);
+ }
+ }
+
+ void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps,
+ ArraySet<AppWindowToken> closingApps) {
+ if (containsHomeTaskWithinDisplay(openingApps)) {
+ setMinimizedDockedStack(true /* minimized */, true /* animate */);
+ } else if (containsHomeTaskWithinDisplay(closingApps)) {
+ setMinimizedDockedStack(false /* minimized */, true /* animate */);
+ }
+ }
+
+ private boolean containsHomeTaskWithinDisplay(ArraySet<AppWindowToken> apps) {
+ for (int i = apps.size() - 1; i >= 0; i--) {
+ final Task task = apps.valueAt(i).mTask;
+ if (task != null && task.isHomeTask()) {
+ return isWithinDisplay(task);
+ }
+ }
+ return false;
+ }
+
+ private boolean isWithinDisplay(Task task) {
+ task.mStack.getBounds(mTmpRect);
+ mDisplayContent.getLogicalDisplayRect(mTmpRect2);
+ return mTmpRect.intersect(mTmpRect2);
+ }
+
+ /**
+ * Sets whether the docked stack is currently in a minimized state, i.e. all the tasks in the
+ * docked stack are heavily clipped so you can only see a minimal peek state.
+ *
+ * @param minimizedDock Whether the docked stack is currently minimized.
+ * @param animate Whether to animate the change.
+ */
+ private void setMinimizedDockedStack(boolean minimizedDock, boolean animate) {
+ if (minimizedDock == mMinimizedDock
+ || mDisplayContent.getDockedStackVisibleForUserLocked() == null) {
+ return;
+ }
+
+ mMinimizedDock = minimizedDock;
+ if (minimizedDock) {
+ if (animate) {
+ startAdjustAnimation(0f, 1f);
+ } else {
+ setMinimizedDockedStack(true);
+ }
+ } else {
+ if (animate) {
+ startAdjustAnimation(1f, 0f);
+ } else {
+ setMinimizedDockedStack(false);
+ }
+ }
+ }
+
+ private void startAdjustAnimation(float from, float to) {
+ mAnimating = true;
+ mAnimationStarted = false;
+ mAnimationStart = from;
+ mAnimationTarget = to;
+ }
+
+ private void setMinimizedDockedStack(boolean minimized) {
+ final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
+ if (stack == null) {
+ return;
+ }
+ if (stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f)) {
+ mService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+ notifyDockedStackMinimizedChanged(minimized, 0);
+ }
+
+ private boolean isAnimationMaximizing() {
+ return mAnimationTarget == 0f;
+ }
+
+ public boolean animate(long now) {
+ if (!mAnimating) {
+ return false;
+ }
+
+ final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked();
+ if (!mAnimationStarted) {
+ mAnimationStarted = true;
+ mAnimationStartTime = now;
+ final long transitionDuration = isAnimationMaximizing()
+ ? mService.mAppTransition.getLastClipRevealTransitionDuration()
+ : DEFAULT_APP_TRANSITION_DURATION;
+ mAnimationDuration = (long)
+ (transitionDuration * mService.getTransitionAnimationScaleLocked());
+ mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
+ notifyDockedStackMinimizedChanged(mMinimizedDock,
+ (long) (mAnimationDuration * mMaximizeMeetFraction));
+ }
+ float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration);
+ t = (isAnimationMaximizing() ? TOUCH_RESPONSE_INTERPOLATOR : mMinimizedDockInterpolator)
+ .getInterpolation(t);
+ if (stack != null) {
+ if (stack.setAdjustedForMinimizedDock(getMinimizeAmount(stack, t))) {
+ mService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+ }
+ if (t >= 1.0f) {
+ mAnimating = false;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
+ */
+ private float getMinimizeAmount(TaskStack stack, float t) {
+ final float naturalAmount = t * mAnimationTarget + (1 - t) * mAnimationStart;
+ if (isAnimationMaximizing()) {
+ return adjustMaximizeAmount(stack, t, naturalAmount);
+ } else {
+ return naturalAmount;
+ }
+ }
+
+ /**
+ * When maximizing the stack during a clip reveal transition, this adjusts the minimize amount
+ * during the transition such that the edge of the clip reveal rect is met earlier in the
+ * transition so we don't create a visible "hole", but only if both the clip reveal and the
+ * docked stack divider start from about the same portion on the screen.
+ */
+ private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
+ if (mMaximizeMeetFraction == 1f) {
+ return naturalAmount;
+ }
+ final int minimizeDistance = stack.getMinimizeDistance();
+ float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
+ / (float) minimizeDistance;
+ final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
+ final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
+ return amountPrime * t2 + naturalAmount * (1 - t2);
+ }
+
+ /**
+ * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
+ * edge. See {@link #adjustMaximizeAmount}.
+ */
+ private float getClipRevealMeetFraction(TaskStack stack) {
+ if (!isAnimationMaximizing() || stack == null ||
+ !mService.mAppTransition.hadClipRevealAnimation()) {
+ return 1f;
+ }
+ final int minimizeDistance = stack.getMinimizeDistance();
+ final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
+ / (float) minimizeDistance;
+ final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
+ / (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
+ return CLIP_REVEAL_MEET_EARLIEST
+ + (1 - t) * (CLIP_REVEAL_MEET_LAST - CLIP_REVEAL_MEET_EARLIEST);
+ }
+
@Override
public boolean isFullscreen() {
return false;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index fe55e80..325005b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -357,6 +357,10 @@
return !mHomeTask && (isResizeable() || mResizeMode == RESIZE_MODE_CROP_WINDOWS);
}
+ boolean isHomeTask() {
+ return mHomeTask;
+ }
+
private boolean inCropWindowsResizeMode() {
return !mHomeTask && !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
}
@@ -639,6 +643,19 @@
return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
}
+ boolean isVisibleForUser() {
+ for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+ final AppWindowToken appToken = mAppTokens.get(i);
+ for (int j = appToken.allAppWindows.size() - 1; j >= 0; j--) {
+ WindowState window = appToken.allAppWindows.get(j);
+ if (!window.isHiddenFromUserLocked()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
boolean inHomeStack() {
return mStack != null && mStack.mStackId == HOME_STACK_ID;
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 8409058..06e5ac5 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -75,9 +75,6 @@
/** Content limits relative to the DisplayContent this sits in. */
private Rect mBounds = new Rect();
- /** Screen content area excluding IM windows, etc. */
- private final Rect mContentBounds = new Rect();
-
/** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
private final Rect mAdjustedBounds = new Rect();
@@ -98,14 +95,27 @@
/** Detach this stack from its display when animation completes. */
boolean mDeferDetach;
- private boolean mUpdateBoundsAfterRotation = false;
+
+ // Display rotation as of the last time the display information was updated for this stack.
+ private int mLastUpdateDisplayInfoRotation = -1;
+ // Display rotation as of the last time the configuration was updated for this stack.
+ private int mLastConfigChangedRotation = -1;
// Whether the stack and all its tasks is currently being drag-resized
private boolean mDragResizing;
+ private final Rect mLastContentBounds = new Rect();
+ private final Rect mTmpAdjustedBounds = new Rect();
+ private boolean mAdjustedForIme;
+ private WindowState mImeWin;
+ private float mMinimizeAmount;
+ private final int mDockedStackMinimizeThickness;
+
TaskStack(WindowManagerService service, int stackId) {
mService = service;
mStackId = stackId;
+ mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.docked_stack_minimize_thickness);
EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
}
@@ -174,7 +184,27 @@
return mTmpRect.equals(bounds);
}
- void alignTasksToAdjustedBounds(final Rect adjustedBounds) {
+ /**
+ * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
+ * the normal task bounds.
+ *
+ * @param bounds The adjusted bounds.
+ * @param keepInsets Whether to keep the insets from the original bounds or to calculate new
+ * ones depending on the adjusted bounds.
+ */
+ private void setAdjustedBounds(Rect bounds, boolean keepInsets) {
+ if (mAdjustedBounds.equals(bounds)) {
+ return;
+ }
+
+ mAdjustedBounds.set(bounds);
+ final boolean adjusted = !mAdjustedBounds.isEmpty();
+ alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds,
+ adjusted && keepInsets ? mBounds : null);
+ mDisplayContent.layoutNeeded = true;
+ }
+
+ private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
if (mFullscreen) {
return;
}
@@ -187,72 +217,15 @@
task.resizeLocked(null, null, false /* forced */);
task.getBounds(mTmpRect2);
task.scrollLocked(mTmpRect2);
- } else if (task.isResizeable()) {
+ } else if (task.isResizeable() && task.mOverrideConfig != Configuration.EMPTY) {
task.getBounds(mTmpRect2);
mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
+ task.setTempInsetBounds(tempInsetBounds);
task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
}
}
}
- void adjustForIME(final WindowState imeWin) {
- final int dockedSide = getDockSide();
- final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
- final Rect adjustedBounds = mAdjustedBounds;
- if (imeWin == null || !dockedTopOrBottom) {
- // If mContentBounds is already empty, it means we're not applying
- // any adjustments, so nothing to do; otherwise clear any adjustments.
- if (!mContentBounds.isEmpty()) {
- mContentBounds.setEmpty();
- adjustedBounds.set(mBounds);
- alignTasksToAdjustedBounds(adjustedBounds);
- }
- return;
- }
-
- final Rect displayContentRect = mTmpRect;
- final Rect contentBounds = mTmpRect2;
-
- // Calculate the content bounds excluding the area occupied by IME
- mDisplayContent.getContentRect(displayContentRect);
- contentBounds.set(displayContentRect);
- int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
- imeTop += imeWin.getGivenContentInsetsLw().top;
- if (contentBounds.bottom > imeTop) {
- contentBounds.bottom = imeTop;
- }
-
- // If content bounds not changing, nothing to do.
- if (mContentBounds.equals(contentBounds)) {
- return;
- }
-
- // Content bounds changed, need to apply adjustments depending on dock sides.
- mContentBounds.set(contentBounds);
- adjustedBounds.set(mBounds);
- final int yOffset = displayContentRect.bottom - contentBounds.bottom;
-
- if (dockedSide == DOCKED_TOP) {
- // If this stack is docked on top, we make it smaller so the bottom stack is not
- // occluded by IME. We shift its bottom up by the height of the IME (capped by
- // the display content rect). Note that we don't change the task bounds.
- adjustedBounds.bottom = Math.max(
- adjustedBounds.bottom - yOffset, displayContentRect.top);
- } else {
- // If this stack is docked on bottom, we shift it up so that it's not occluded by
- // IME. We try to move it up by the height of the IME window (although the best
- // we could do is to make the top stack fully collapsed).
- final int dividerWidth = mDisplayContent.mDividerControllerLocked.getContentWidth();
- adjustedBounds.top = Math.max(
- adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
- adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
-
- // We also move the member tasks together, taking care not to resize them.
- // Resizing might cause relaunch, and IME window may not come back after that.
- alignTasksToAdjustedBounds(adjustedBounds);
- }
- }
-
private boolean setBounds(Rect bounds) {
boolean oldFullscreen = mFullscreen;
int rotation = Surface.ROTATION_0;
@@ -281,14 +254,7 @@
mBounds.set(bounds);
mRotation = rotation;
- // Clear the adjusted content bounds as they're no longer valid.
- // If IME is still visible, these will be re-applied.
- // Note that we don't clear mContentBounds here, so that we know the last IME
- // adjust we applied.
- // If user starts dragging the dock divider while IME is visible, the new bounds
- // we received are based on the actual screen location of the divider. It already
- // accounted for the IME window, so we don't want to adjust again.
- mAdjustedBounds.set(mBounds);
+ updateAdjustedBounds();
return true;
}
@@ -314,10 +280,11 @@
public void getBounds(Rect out) {
if (useCurrentBounds()) {
- // If we're currently adjusting for IME, we use the adjusted bounds; otherwise,
- // no need to adjust the output bounds if fullscreen or the docked stack is visible
- // since it is already what we want to represent to the rest of the system.
- if (!mContentBounds.isEmpty()) {
+ // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
+ // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
+ // stack is visible since it is already what we want to represent to the rest of the
+ // system.
+ if (!mAdjustedBounds.isEmpty()) {
out.set(mAdjustedBounds);
} else {
out.set(mBounds);
@@ -338,39 +305,51 @@
}
void updateDisplayInfo(Rect bounds) {
- mUpdateBoundsAfterRotation = false;
- if (mDisplayContent != null) {
- for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
- mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
- }
- if (bounds != null) {
- setBounds(bounds);
- } else if (mFullscreen) {
- setBounds(null);
- } else {
- mUpdateBoundsAfterRotation = true;
- mTmpRect2.set(mBounds);
- final int newRotation = mDisplayContent.getDisplayInfo().rotation;
- if (mRotation == newRotation) {
- setBounds(mTmpRect2);
- }
+ if (mDisplayContent == null) {
+ return;
+ }
- // If the rotation changes, we'll handle it in updateBoundsAfterRotation
- }
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
+ }
+ if (bounds != null) {
+ setBounds(bounds);
+ return;
+ } else if (mFullscreen) {
+ setBounds(null);
+ return;
+ }
+
+ mTmpRect2.set(mBounds);
+ final int newRotation = mDisplayContent.getDisplayInfo().rotation;
+ if (mRotation == newRotation) {
+ setBounds(mTmpRect2);
+ } else {
+ mLastUpdateDisplayInfoRotation = newRotation;
+ updateBoundsAfterRotation();
}
}
- /**
- * Updates the bounds after rotating the screen. We can't handle it in
- * {@link #updateDisplayInfo} because at that point the configuration might not be fully updated
- * yet.
- */
+ void onConfigurationChanged() {
+ mLastConfigChangedRotation = getDisplayInfo().rotation;
+ updateBoundsAfterRotation();
+ }
+
void updateBoundsAfterRotation() {
- if (!mUpdateBoundsAfterRotation) {
+ if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) {
+ // We wait for the rotation values after configuration change and display info. update
+ // to be equal before updating the bounds due to rotation change otherwise things might
+ // get out of alignment...
return;
}
- mUpdateBoundsAfterRotation = false;
+
final int newRotation = getDisplayInfo().rotation;
+
+ if (mRotation == newRotation) {
+ // Nothing to do here if the rotation didn't change
+ return;
+ }
+
mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
if (mStackId == DOCKED_STACK_ID) {
snapDockedStackAfterRotation(mTmpRect2);
@@ -379,8 +358,8 @@
// Post message to inform activity manager of the bounds change simulating
// a one-way call. We do this to prevent a deadlock between window manager
// lock and activity manager lock been held.
- mService.mH.sendMessage(mService.mH.obtainMessage(
- RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2));
+ mService.mH.obtainMessage(
+ RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
}
/**
@@ -420,7 +399,7 @@
final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
- if (winAnimator.isAnimating() || winAnimator.mWin.mExiting) {
+ if (winAnimator.isAnimating() || winAnimator.mWin.mAnimatingExit) {
return true;
}
}
@@ -691,7 +670,7 @@
outBounds.top = dockedBounds.bottom + dockDividerWidth;
}
}
- DockedDividerUtils.sanitizeStackBounds(outBounds);
+ DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
}
/** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
@@ -802,6 +781,158 @@
mDisplayContent = null;
}
+ /**
+ * Adjusts the stack bounds if the IME is visible.
+ *
+ * @param imeWin The IME window.
+ */
+ void setAdjustedForIme(WindowState imeWin) {
+ mAdjustedForIme = true;
+ mImeWin = imeWin;
+ updateAdjustedBounds();
+ }
+
+ /**
+ * Resets the adjustment after it got adjusted for the IME.
+ */
+ void resetAdjustedForIme() {
+ mAdjustedForIme = false;
+ mImeWin = null;
+ updateAdjustedBounds();
+ }
+
+ /**
+ * Sets the amount how much we currently minimize our stack.
+ *
+ * @param minimizeAmount The amount, between 0 and 1.
+ * @return Whether the amount has changed and a layout is needed.
+ */
+ boolean setAdjustedForMinimizedDock(float minimizeAmount) {
+ if (minimizeAmount != mMinimizeAmount) {
+ mMinimizeAmount = minimizeAmount;
+ updateAdjustedBounds();
+ return isVisibleForUserLocked();
+ } else {
+ return false;
+ }
+ }
+
+ private boolean adjustForIME(final WindowState imeWin) {
+ final int dockedSide = getDockSide();
+ final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
+ final Rect adjustedBounds = mTmpAdjustedBounds;
+ if (imeWin == null || !dockedTopOrBottom) {
+ return false;
+ }
+
+ final Rect displayContentRect = mTmpRect;
+ final Rect contentBounds = mTmpRect2;
+
+ // Calculate the content bounds excluding the area occupied by IME
+ getDisplayContent().getContentRect(displayContentRect);
+ contentBounds.set(displayContentRect);
+ int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
+ imeTop += imeWin.getGivenContentInsetsLw().top;
+ if (contentBounds.bottom > imeTop) {
+ contentBounds.bottom = imeTop;
+ }
+
+ // If content bounds not changing, nothing to do.
+ if (mLastContentBounds.equals(contentBounds)) {
+ return true;
+ }
+
+ // Content bounds changed, need to apply adjustments depending on dock sides.
+ mLastContentBounds.set(contentBounds);
+ adjustedBounds.set(mBounds);
+ final int yOffset = displayContentRect.bottom - contentBounds.bottom;
+
+ if (dockedSide == DOCKED_TOP) {
+ // If this stack is docked on top, we make it smaller so the bottom stack is not
+ // occluded by IME. We shift its bottom up by the height of the IME (capped by
+ // the display content rect). Note that we don't change the task bounds.
+ adjustedBounds.bottom = Math.max(
+ adjustedBounds.bottom - yOffset, displayContentRect.top);
+ } else {
+ // If this stack is docked on bottom, we shift it up so that it's not occluded by
+ // IME. We try to move it up by the height of the IME window (although the best
+ // we could do is to make the top stack fully collapsed).
+ final int dividerWidth = getDisplayContent().mDividerControllerLocked
+ .getContentWidth();
+ adjustedBounds.top = Math.max(
+ adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
+ adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
+ }
+ return true;
+ }
+
+ private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
+ final int dockSide = getDockSide();
+ if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
+ return false;
+ }
+
+ if (dockSide == DOCKED_TOP) {
+ mService.getStableInsetsLocked(mTmpRect);
+ int topInset = mTmpRect.top;
+ mTmpAdjustedBounds.set(mBounds);
+ mTmpAdjustedBounds.bottom =
+ (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
+ } else if (dockSide == DOCKED_LEFT) {
+ mTmpAdjustedBounds.set(mBounds);
+ mTmpAdjustedBounds.right =
+ (int) (minimizeAmount * mDockedStackMinimizeThickness
+ + (1 - minimizeAmount) * mBounds.right);
+ } else if (dockSide == DOCKED_RIGHT) {
+ mTmpAdjustedBounds.set(mBounds);
+ mTmpAdjustedBounds.left =
+ (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness)
+ + (1 - minimizeAmount) * mBounds.left);
+ }
+ return true;
+ }
+
+ /**
+ * @return the distance in pixels how much the stack gets minimized from it's original size
+ */
+ int getMinimizeDistance() {
+ final int dockSide = getDockSide();
+ if (dockSide == DOCKED_INVALID) {
+ return 0;
+ }
+
+ if (dockSide == DOCKED_TOP) {
+ mService.getStableInsetsLocked(mTmpRect);
+ int topInset = mTmpRect.top;
+ return mBounds.bottom - topInset;
+ } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
+ return mBounds.width() - mDockedStackMinimizeThickness;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Updates the adjustment depending on it's current state.
+ */
+ void updateAdjustedBounds() {
+ boolean adjust = false;
+ if (mMinimizeAmount != 0f) {
+ adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
+ } else if (mAdjustedForIme) {
+ adjust = adjustForIME(mImeWin);
+ }
+ if (!adjust) {
+ mTmpAdjustedBounds.setEmpty();
+ mLastContentBounds.setEmpty();
+ }
+ setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack());
+ }
+
+ boolean isAdjustedForMinimizedDockedStack() {
+ return mMinimizeAmount != 0f;
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "mStackId=" + mStackId);
pw.println(prefix + "mDeferDetach=" + mDeferDetach);
@@ -906,13 +1037,28 @@
}
for (int i = mTasks.size() - 1; i >= 0; i--) {
- Task task = mTasks.get(i);
+ final Task task = mTasks.get(i);
for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
if (!task.mAppTokens.get(j).hidden) {
return true;
}
}
}
+
+ return false;
+ }
+
+ /**
+ * @return true if a the stack is visible for the current in user, ignoring any other visibility
+ * aspects, and false otherwise
+ */
+ boolean isVisibleForUserLocked() {
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ final Task task = mTasks.get(i);
+ if (task.isVisibleForUser()) {
+ return true;
+ }
+ }
return false;
}
@@ -979,4 +1125,4 @@
public void getFullScreenBounds(Rect bounds) {
getDisplayContent().getContentRect(bounds);
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index f8a4d33..38d0711 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -705,7 +705,8 @@
}
orAnimating(mService.getDisplayContentLocked(displayId).animateDimLayers());
-
+ orAnimating(mService.getDisplayContentLocked(displayId).getDockedDividerController()
+ .animate(mCurrentTime));
//TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null
&& displayId == Display.DEFAULT_DISPLAY) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7169375..142715e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -116,7 +116,7 @@
import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManagerInternal;
import android.widget.Toast;
-import com.android.internal.R;
+
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.FastPrintWriter;
@@ -192,6 +192,8 @@
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
+import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
@@ -1354,7 +1356,7 @@
+ " policyVis=" + w.mPolicyVisibility
+ " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim
+ " attachHid=" + w.mAttachedHidden
- + " exiting=" + w.mExiting + " destroying=" + w.mDestroying);
+ + " exiting=" + w.mAnimatingExit + " destroying=" + w.mDestroying);
if (w.mAppToken != null) {
Slog.i(TAG_WM, " mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested);
}
@@ -2057,7 +2059,7 @@
WindowState replacedWindow = null;
for (int i = atoken.windows.size() - 1; i >= 0 && replacedWindow == null; i--) {
WindowState candidate = atoken.windows.get(i);
- if (candidate.mExiting && candidate.mWillReplaceWindow
+ if (candidate.mAnimatingExit && candidate.mWillReplaceWindow
&& candidate.mAnimateReplacingWindow) {
replacedWindow = candidate;
}
@@ -2131,19 +2133,12 @@
if (win == null) {
return;
}
- // We set this here instead of removeWindowLocked because we only want it to be
- // true when the client has requested we remove the window. In other remove
- // cases, we have to wait for activity stop to safely remove the window (as the
- // client may still be using the surface). In this case though, the client has
- // just dismissed a window (for example a Dialog) and activity stop isn't
- // necessarily imminent, so we need to know not to wait for it after our
- // hanimation (if applicable) finishes.
- win.mClientRemoveRequested = true;
removeWindowLocked(win);
}
}
void removeWindowLocked(WindowState win) {
+ win.mWindowRemovalAllowed = true;
final boolean startingWindow = win.mAttrs.type == TYPE_APPLICATION_STARTING;
if (startingWindow) {
if (DEBUG_STARTING_WINDOW) Slog.d(TAG_WM, "Starting window removed " + win);
@@ -2159,23 +2154,25 @@
win.disposeInputChannel();
- if (DEBUG_APP_TRANSITIONS) Slog.v(
- TAG_WM, "Remove " + win + ": mSurfaceController=" + win.mWinAnimator.mSurfaceController
- + " mExiting=" + win.mExiting
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+ "Remove " + win + ": mSurfaceController=" + win.mWinAnimator.mSurfaceController
+ + " mAnimatingExit=" + win.mAnimatingExit
+ + " mRemoveOnExit=" + win.mRemoveOnExit
+ + " mHasSurface=" + win.mHasSurface
+ + " surfaceShowing=" + win.mWinAnimator.getShown()
+ " isAnimating=" + win.mWinAnimator.isAnimating()
+ " app-animation="
+ (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null)
- + " mWillReplaceWindow="
- + win.mWillReplaceWindow
+ + " mWillReplaceWindow=" + win.mWillReplaceWindow
+ " inPendingTransaction="
+ (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
- + " mDisplayFrozen=" + mDisplayFrozen);
+ + " mDisplayFrozen=" + mDisplayFrozen
+ + " callers=" + Debug.getCallers(6));
// Visibility of the removed window. Will be used later to update orientation later on.
boolean wasVisible = false;
- // First, see if we need to run an animation. If we do, we have
- // to hold off on removing the window until the animation is done.
- // If the display is frozen, just remove immediately, since the
- // animation wouldn't be seen.
+ // First, see if we need to run an animation. If we do, we have to hold off on removing the
+ // window until the animation is done. If the display is frozen, just remove immediately,
+ // since the animation wouldn't be seen.
if (win.mHasSurface && okToDisplay()) {
final AppWindowToken appToken = win.mAppToken;
if (win.mWillReplaceWindow) {
@@ -2183,13 +2180,16 @@
// gets added, then we will get rid of this one.
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Preserving " + win + " until the new one is "
+ "added");
- win.mExiting = true;
+ // TODO: We are overloading mAnimatingExit flag to prevent the window state from
+ // been removed. We probably need another falg to indicate that window removal
+ // should be deffered vs. overloading the flag that says we are playing an exit
+ // animation.
+ win.mAnimatingExit = true;
win.mReplacingRemoveRequested = true;
Binder.restoreCallingIdentity(origId);
return;
}
- // If we are not currently running the exit animation, we
- // need to see about starting one.
+ // If we are not currently running the exit animation, we need to see about starting one
wasVisible = win.isWinVisibleLw();
if (win.shouldKeepVisibleDeadAppWindow()) {
@@ -2209,14 +2209,13 @@
return;
}
+ final WindowStateAnimator winAnimator = win.mWinAnimator;
if (wasVisible) {
- final int transit = (!startingWindow)
- ? WindowManagerPolicy.TRANSIT_EXIT
- : WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+ final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
// Try starting an animation.
- if (win.mWinAnimator.applyAnimationLocked(transit, false)) {
- win.mExiting = true;
+ if (winAnimator.applyAnimationLocked(transit, false)) {
+ win.mAnimatingExit = true;
}
//TODO (multidisplay): Magnification is supported only for the default display.
if (mAccessibilityController != null
@@ -2224,15 +2223,20 @@
mAccessibilityController.onWindowTransitionLocked(win, transit);
}
}
- final boolean isAnimating = win.mWinAnimator.isAnimating()
- && !win.mWinAnimator.isDummyAnimation();
- // The starting window is the last window in this app token and it isn't animating.
- // Allow it to be removed now as there is no additional window or animation that will
- // trigger its removal.
- final boolean lastWinStartingNotAnimating = startingWindow && appToken!= null
- && appToken.allAppWindows.size() == 1 && !isAnimating;
- if (!lastWinStartingNotAnimating && win.mExiting) {
- // The exit animation is running... wait for it!
+ final boolean isAnimating =
+ winAnimator.isAnimating() && !winAnimator.isDummyAnimation();
+ final boolean lastWindowIsStartingWindow = startingWindow && appToken != null
+ && appToken.allAppWindows.size() == 1;
+ // We delay the removal of a window if it has a showing surface that can be used to run
+ // exit animation and it is marked as exiting.
+ // Also, If isn't the an animating starting window that is the last window in the app.
+ // We allow the removal of the non-animating starting window now as there is no
+ // additional window or animation that will trigger its removal.
+ if (winAnimator.getShown() && win.mAnimatingExit
+ && (!lastWindowIsStartingWindow || isAnimating)) {
+ // The exit animation is running or should run... wait for it!
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ "Not removing " + win + " due to exit animation ");
win.mRemoveOnExit = true;
win.setDisplayLayoutNeeded();
final boolean focusChanged = updateFocusedWindowLocked(
@@ -2262,13 +2266,14 @@
void removeWindowInnerLocked(WindowState win) {
if (win.mRemoved) {
// Nothing to do.
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ "removeWindowInnerLocked: " + win + " Already removed...");
return;
}
- for (int i=win.mChildWindows.size()-1; i>=0; i--) {
+ for (int i = win.mChildWindows.size() - 1; i >= 0; i--) {
WindowState cwin = win.mChildWindows.get(i);
- Slog.w(TAG_WM, "Force-removing child win " + cwin + " from container "
- + win);
+ Slog.w(TAG_WM, "Force-removing child win " + cwin + " from container " + win);
removeWindowInnerLocked(cwin);
}
@@ -2681,16 +2686,16 @@
final boolean usingSavedSurfaceBeforeVisible =
oldVisibility != View.VISIBLE && win.isAnimatingWithSavedSurface();
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- if (winAnimator.hasSurface() && !win.mExiting
+ if (winAnimator.hasSurface() && !win.mAnimatingExit
&& usingSavedSurfaceBeforeVisible) {
Slog.d(TAG, "Ignoring layout to invisible when using saved surface " + win);
}
}
- if (winAnimator.hasSurface() && !win.mExiting
+ if (winAnimator.hasSurface() && !win.mAnimatingExit
&& !usingSavedSurfaceBeforeVisible) {
if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Relayout invis " + win
- + ": mExiting=" + win.mExiting);
+ + ": mAnimatingExit=" + win.mAnimatingExit);
// If we are not currently running the exit animation, we
// need to see about starting one.
// We don't want to animate visibility of windows which are pending
@@ -2797,16 +2802,16 @@
}
if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = isDefaultDisplay;
- win.mExiting = true;
+ win.mAnimatingExit = true;
} else if (win.mWinAnimator.isAnimating()) {
// Currently in a hide animation... turn this into
// an exit.
- win.mExiting = true;
+ win.mAnimatingExit = true;
} else if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
// If the wallpaper is currently behind this
// window, we need to change both of them inside
// of a transaction to avoid artifacts.
- win.mExiting = true;
+ win.mAnimatingExit = true;
win.mWinAnimator.mAnimating = true;
} else {
if (mInputMethodWindow == win) {
@@ -2842,12 +2847,12 @@
private int relayoutVisibleWindow(Configuration outConfig, int result, WindowState win,
WindowStateAnimator winAnimator, int attrChanges, int oldVisibility) {
result |= !win.isVisibleLw() ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0;
- if (win.mExiting) {
- Slog.d(TAG, "relayoutVisibleWindow: " + win + " mExiting=true, mRemoveOnExit="
+ if (win.mAnimatingExit) {
+ Slog.d(TAG, "relayoutVisibleWindow: " + win + " mAnimatingExit=true, mRemoveOnExit="
+ win.mRemoveOnExit + ", mDestroying=" + win.mDestroying);
winAnimator.cancelExitAnimationForNextAnimationLocked();
- win.mExiting = false;
+ win.mAnimatingExit = false;
}
if (win.mDestroying) {
win.mDestroying = false;
@@ -2968,6 +2973,8 @@
// Determine the visible rect to calculate the thumbnail clip
final WindowState win = atoken.findMainWindow();
final Rect frame = new Rect(0, 0, width, height);
+ final Rect displayFrame = new Rect(0, 0,
+ displayInfo.logicalWidth, displayInfo.logicalHeight);
final Rect insets = new Rect();
Rect surfaceInsets = null;
final boolean freeform = win != null && win.inFreeformWorkspace();
@@ -2995,8 +3002,8 @@
+ " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
+ " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
Animation a = mAppTransition.loadAnimation(lp, transit, enter,
- mCurConfiguration.orientation, frame, insets, surfaceInsets, isVoiceInteraction,
- freeform, atoken.mTask.mTaskId);
+ mCurConfiguration.orientation, frame, displayFrame, insets, surfaceInsets,
+ isVoiceInteraction, freeform, atoken.mTask.mTaskId);
if (a != null) {
if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken);
final int containingWidth = frame.width();
@@ -3542,23 +3549,20 @@
}
synchronized(mWindowMap) {
- final boolean orientationChanged = mCurConfiguration.orientation != config.orientation;
mCurConfiguration = new Configuration(config);
if (mWaitingForConfig) {
mWaitingForConfig = false;
mLastFinishedFreezeSource = "new-config";
}
- if (orientationChanged) {
- updateTaskStackBoundsAfterRotation();
- }
+ onConfigurationChanged();
mWindowPlacerLocked.performSurfacePlacement();
}
}
- private void updateTaskStackBoundsAfterRotation() {
+ private void onConfigurationChanged() {
for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
- stack.updateBoundsAfterRotation();
+ stack.onConfigurationChanged();
}
}
@@ -4153,11 +4157,15 @@
}
}
- if (visibilityChanged && visible && !delayed) {
- // The token was made immediately visible, there will be no entrance animation. We need
- // to inform the client the enter animation was finished.
- wtoken.mEnteringAnimation = true;
- mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(wtoken.token);
+ if (visibilityChanged && !delayed) {
+ if (visible) {
+ // The token was made immediately visible, there will be no entrance animation.
+ // We need to inform the client the enter animation was finished.
+ wtoken.mEnteringAnimation = true;
+ mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(wtoken.token);
+ }
+ getDefaultDisplayContentLocked().getDockedDividerController()
+ .notifyAppVisibilityChanged(wtoken, visible);
}
return delayed;
@@ -4224,6 +4232,7 @@
wtoken.removeAllWindows();
} else if (visible) {
wtoken.mAppStopped = false;
+ wtoken.setWindowsExiting(false);
}
// If we are preparing an app transition, then delay changing
@@ -4241,7 +4250,6 @@
}
wtoken.inPendingTransaction = true;
if (visible) {
- wtoken.setWindowsExiting(false);
mOpeningApps.add(wtoken);
wtoken.startingMoved = false;
wtoken.mEnteringAnimation = true;
@@ -8124,14 +8132,14 @@
for (int i = stacks.size() - 1; i >= 0; --i) {
final TaskStack stack = stacks.get(i);
if (stack.isVisibleLocked()) {
- stack.adjustForIME(imeWin);
+ stack.setAdjustedForIme(imeWin);
}
}
} else {
final ArrayList<TaskStack> stacks = displayContent.getStacks();
for (int i = stacks.size() - 1; i >= 0; --i) {
final TaskStack stack = stacks.get(i);
- stack.adjustForIME(null);
+ stack.resetAdjustedForIme();
}
}
}
@@ -8984,11 +8992,10 @@
EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
winAnimator.mSession.mPid, operation);
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
- // There was some problem... first, do a sanity check of the
- // window list to make sure we haven't left any dangling surfaces
- // around.
+ // There was some problem... first, do a sanity check of the window list to make sure
+ // we haven't left any dangling surfaces around.
Slog.i(TAG_WM, "Out of memory for surface! Looking for leaks...");
final int numDisplays = mDisplayContents.size();
@@ -8997,28 +9004,27 @@
final int numWindows = windows.size();
for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
final WindowState ws = windows.get(winNdx);
- WindowStateAnimator wsa = ws.mWinAnimator;
- if (wsa.mSurfaceController != null) {
- if (!mSessions.contains(wsa.mSession)) {
- Slog.w(TAG_WM, "LEAKED SURFACE (session doesn't exist): "
- + ws + " surface=" + wsa.mSurfaceController
- + " token=" + ws.mToken
- + " pid=" + ws.mSession.mPid
- + " uid=" + ws.mSession.mUid);
- wsa.destroySurface();
- ws.setHasSurface(false);
- mForceRemoves.add(ws);
- leakedSurface = true;
- } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
- Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
- + ws + " surface=" + wsa.mSurfaceController
- + " token=" + ws.mAppToken
- + " saved=" + ws.mAppToken.hasSavedSurface());
- if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false);
- wsa.destroySurface();
- ws.setHasSurface(false);
- leakedSurface = true;
- }
+ final WindowStateAnimator wsa = ws.mWinAnimator;
+ if (wsa.mSurfaceController == null) {
+ continue;
+ }
+ if (!mSessions.contains(wsa.mSession)) {
+ Slog.w(TAG_WM, "LEAKED SURFACE (session doesn't exist): "
+ + ws + " surface=" + wsa.mSurfaceController
+ + " token=" + ws.mToken
+ + " pid=" + ws.mSession.mPid
+ + " uid=" + ws.mSession.mUid);
+ wsa.destroySurface();
+ mForceRemoves.add(ws);
+ leakedSurface = true;
+ } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
+ Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
+ + ws + " surface=" + wsa.mSurfaceController
+ + " token=" + ws.mAppToken
+ + " saved=" + ws.mAppToken.hasSavedSurface());
+ if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false);
+ wsa.destroySurface();
+ leakedSurface = true;
}
}
}
@@ -9061,8 +9067,7 @@
if (surfaceController != null) {
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
"RECOVER DESTROY", false);
- surfaceController.destroyInTransaction();
- winAnimator.mWin.setHasSurface(false);
+ winAnimator.destroySurface();
scheduleRemoveStartingWindowLocked(winAnimator.mWin.mAppToken);
}
@@ -10336,7 +10341,8 @@
@Override
public int getDockedStackSide() {
synchronized (mWindowMap) {
- TaskStack dockedStack = getDefaultDisplayContentLocked().getDockedStackLocked();
+ final TaskStack dockedStack = getDefaultDisplayContentLocked()
+ .getDockedStackVisibleForUserLocked();
return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide();
}
}
@@ -10420,11 +10426,16 @@
}
}
- private void getStableInsetsLocked(Rect outInsets) {
+ void getStableInsetsLocked(Rect outInsets) {
final DisplayInfo di = getDefaultDisplayInfoLocked();
mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
}
+ private void getNonDecorInsetsLocked(Rect outInsets) {
+ final DisplayInfo di = getDefaultDisplayInfoLocked();
+ mPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
+ }
+
/**
* Intersects the specified {@code inOutBounds} with the display frame that excludes the stable
* inset areas.
@@ -10441,6 +10452,23 @@
}
}
+ /**
+ * Intersects the specified {@code inOutBounds} with the display frame that excludes
+ * areas that could never be removed in Honeycomb. See
+ * {@link WindowManagerPolicy#getNonDecorInsetsLw}.
+ *
+ * @param inOutBounds The inOutBounds to subtract the inset areas from.
+ */
+ public void subtractNonDecorInsets(Rect inOutBounds) {
+ synchronized (mWindowMap) {
+ getNonDecorInsetsLocked(mTmpRect2);
+ final DisplayInfo di = getDefaultDisplayInfoLocked();
+ mTmpRect.set(0, 0, di.logicalWidth, di.logicalHeight);
+ mTmpRect.inset(mTmpRect2);
+ inOutBounds.intersect(mTmpRect);
+ }
+ }
+
private MousePositionTracker mMousePositionTracker = new MousePositionTracker();
private static class MousePositionTracker implements PointerEventListener {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bea333b..f30c8d3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -358,7 +358,7 @@
boolean mLayoutNeeded;
/** Currently running an exit animation? */
- boolean mExiting;
+ boolean mAnimatingExit;
/** Currently on the mDestroySurface list? */
boolean mDestroying;
@@ -387,11 +387,11 @@
boolean mRemoved;
/**
- * Has the client requested we remove the window? In this case we know
- * that we can dispose of it when we wish without further synchronization
- * with the client
+ * It is save to remove the window and destroy the surface because the client requested removal
+ * or some other higher level component said so (e.g. activity manager).
+ * TODO: We should either have different booleans for the removal reason or use a bit-field.
*/
- boolean mClientRemoveRequested;
+ boolean mWindowRemovalAllowed;
/**
* Temp for keeping track of windows that have been removed when
@@ -614,7 +614,7 @@
@Override
public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf, Rect sf,
Rect osf) {
- if (mWillReplaceWindow && (mExiting || !mReplacingRemoveRequested)) {
+ if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
// This window is being replaced and either already got information that it's being
// removed or we are still waiting for some information. Because of this we don't
// want to apply any more changes to it, so it remains in this state until new window
@@ -1075,7 +1075,7 @@
*/
private boolean isVisibleUnchecked() {
return mHasSurface && mPolicyVisibility && !mAttachedHidden
- && !mExiting && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
+ && !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
}
/**
@@ -1100,7 +1100,7 @@
}
final AppWindowToken atoken = mAppToken;
final boolean animating = atoken != null && atoken.mAppAnimator.animation != null;
- return mHasSurface && !mDestroying && !mExiting
+ return mHasSurface && !mDestroying && !mAnimatingExit
&& (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
&& ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden)
|| mWinAnimator.mAnimation != null || animating);
@@ -1143,7 +1143,7 @@
return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
&& mPolicyVisibility && !mAttachedHidden
&& (atoken == null || !atoken.hiddenRequested)
- && !mExiting && !mDestroying;
+ && !mAnimatingExit && !mDestroying;
}
/**
@@ -1237,7 +1237,7 @@
|| (atoken == null && mRootToken.hidden)
|| (atoken != null && (atoken.hiddenRequested || atoken.hidden))
|| mAttachedHidden
- || (mExiting && !isAnimatingLw())
+ || (mAnimatingExit && !isAnimatingLw())
|| mDestroying;
}
@@ -1283,7 +1283,7 @@
*/
boolean hasMoved() {
return mHasSurface && (mContentChanged || mMovedByResize)
- && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
+ && !mAnimatingExit && !mWinAnimator.mLastHidden && mService.okToDisplay()
&& (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
&& (mAttachedWindow == null || !mAttachedWindow.hasMoved());
}
@@ -1438,11 +1438,11 @@
return;
}
- if (!mExiting && mAppDied) {
+ if (!mAnimatingExit && mAppDied) {
// If app died visible, apply a dim over the window to indicate that it's inactive
mDisplayContent.mDimLayerController.applyDimAbove(getDimLayerUser(), mWinAnimator);
} else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0
- && mDisplayContent != null && !mExiting && isDisplayedLw()) {
+ && mDisplayContent != null && !mAnimatingExit && isDisplayedLw()) {
mDisplayContent.mDimLayerController.applyDimBehind(getDimLayerUser(), mWinAnimator);
}
}
@@ -1467,7 +1467,7 @@
win.mAnimateReplacingWindow = false;
win.mReplacingRemoveRequested = false;
win.mReplacingWindow = null;
- if (win.mExiting) {
+ if (win.mAnimatingExit) {
mService.removeWindowInnerLocked(win);
}
}
@@ -1810,7 +1810,7 @@
}
boolean isClosing() {
- return mExiting || (mService.mClosingApps.contains(mAppToken));
+ return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
}
boolean isAnimatingWithSavedSurface() {
@@ -1868,6 +1868,9 @@
}
public void restoreSavedSurface() {
+ if (!mSurfaceSaved) {
+ return;
+ }
mSurfaceSaved = false;
setHasSurface(true);
mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
@@ -2162,6 +2165,11 @@
if (task == null) {
return false;
}
+ if (mAttrs.width != MATCH_PARENT || mAttrs.height != MATCH_PARENT) {
+
+ // Floating windows never enter drag resize mode.
+ return false;
+ }
if (task.isDragResizing()) {
return true;
}
@@ -2333,8 +2341,8 @@
}
pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
mWinAnimator.dump(pw, prefix + " ", dumpAll);
- if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
- pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
+ if (mAnimatingExit || mRemoveOnExit || mDestroying || mRemoved) {
+ pw.print(prefix); pw.print("mAnimatingExit="); pw.print(mAnimatingExit);
pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
pw.print(" mDestroying="); pw.print(mDestroying);
pw.print(" mRemoved="); pw.println(mRemoved);
@@ -2395,12 +2403,12 @@
@Override
public String toString() {
final CharSequence title = getWindowTag();
- if (mStringNameCache == null || mLastTitle != title || mWasExiting != mExiting) {
+ if (mStringNameCache == null || mLastTitle != title || mWasExiting != mAnimatingExit) {
mLastTitle = title;
- mWasExiting = mExiting;
+ mWasExiting = mAnimatingExit;
mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this))
+ " u" + UserHandle.getUserId(mSession.mUid)
- + " " + mLastTitle + (mExiting ? " EXITING}" : "}");
+ + " " + mLastTitle + (mAnimatingExit ? " EXITING}" : "}");
}
return mStringNameCache;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0201296..0828417 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -29,7 +29,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -375,7 +374,7 @@
// Done animating, clean up.
if (DEBUG_ANIM) Slog.v(
- TAG, "Animation done in " + this + ": exiting=" + mWin.mExiting
+ TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
+ ", reportedVisible="
+ (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
@@ -430,7 +429,7 @@
void finishExit() {
if (DEBUG_ANIM) Slog.v(
TAG, "finishExit in " + this
- + ": exiting=" + mWin.mExiting
+ + ": exiting=" + mWin.mAnimatingExit
+ " remove=" + mWin.mRemoveOnExit
+ " windowAnimating=" + isWindowAnimating());
@@ -460,7 +459,7 @@
}
}
- if (!mWin.mExiting) {
+ if (!mWin.mAnimatingExit) {
return;
}
@@ -475,27 +474,27 @@
mWin.mDestroying = true;
+ final boolean hasSurface = hasSurface();
+ if (hasSurface) {
+ hide("finishExit");
+ }
+
// If we have an app token, we ask it to destroy the surface for us,
// so that it can take care to ensure the activity has actually stopped
// and the surface is not still in use. Otherwise we add the service to
// mDestroySurface and allow it to be processed in our next transaction.
if (mWin.mAppToken != null) {
- if (hasSurface()) {
- hide("finishExit");
- }
mWin.mAppToken.destroySurfaces();
} else {
- if (hasSurface()) {
+ if (hasSurface) {
mService.mDestroySurface.add(mWin);
- hide("finishExit");
}
- mWin.mExiting = false;
if (mWin.mRemoveOnExit) {
mService.mPendingRemove.add(mWin);
mWin.mRemoveOnExit = false;
}
}
-
+ mWin.mAnimatingExit = false;
mWallpaperControllerLocked.hideWallpapers(mWin);
}
@@ -557,14 +556,21 @@
if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
result = performShowLocked();
}
- if (mDestroyPreservedSurfaceUponRedraw) {
- mService.mDestroyPreservedSurface.add(mWin);
- }
return result;
}
void preserveSurfaceLocked() {
if (mDestroyPreservedSurfaceUponRedraw) {
+ // This could happen when switching the surface mode very fast. For example,
+ // we preserved a surface when dragResizing changed to true. Then before the
+ // preserved surface is removed, dragResizing changed to false again.
+ // In this case, we need to leave the preserved surface alone, and destroy
+ // the actual surface, so that the createSurface call could create a surface
+ // of the proper size. The preserved surface will still be removed when client
+ // finishes drawing to the new surface.
+ mSurfaceDestroyDeferred = false;
+ destroySurfaceLocked();
+ mSurfaceDestroyDeferred = true;
return;
}
if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "SET FREEZE LAYER", false);
@@ -593,119 +599,118 @@
return mSurfaceController;
}
- if (mSurfaceController == null) {
- if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
- "createSurface " + this + ": mDrawState=DRAW_PENDING");
- mDrawState = DRAW_PENDING;
- if (w.mAppToken != null) {
- if (w.mAppToken.mAppAnimator.animation == null) {
- w.mAppToken.allDrawn = false;
- w.mAppToken.deferClearAllDrawn = false;
- } else {
- // Currently animating, persist current state of allDrawn until animation
- // is complete.
- w.mAppToken.deferClearAllDrawn = true;
- }
- }
-
- mService.makeWindowFreezingScreenIfNeededLocked(w);
-
- int flags = SurfaceControl.HIDDEN;
- final WindowManager.LayoutParams attrs = w.mAttrs;
-
- if (mService.isSecureLocked(w)) {
- flags |= SurfaceControl.SECURE;
- }
-
- mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
- calculateSurfaceBounds(w, attrs);
- final int width = mTmpSize.width();
- final int height = mTmpSize.height();
-
- if (DEBUG_VISIBILITY) {
- Slog.v(TAG, "Creating surface in session "
- + mSession.mSurfaceSession + " window " + this
- + " w=" + width + " h=" + height
- + " x=" + mTmpSize.left + " y=" + mTmpSize.top
- + " format=" + attrs.format + " flags=" + flags);
- }
-
- // We may abort, so initialize to defaults.
- mLastSystemDecorRect.set(0, 0, 0, 0);
- mHasClipRect = false;
- mClipRect.set(0, 0, 0, 0);
- mLastClipRect.set(0, 0, 0, 0);
-
- // Set up surface control with initial size.
- try {
-
- final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
- final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
- if (!PixelFormat.formatHasAlpha(attrs.format)
- // Don't make surface with surfaceInsets opaque as they display a
- // translucent shadow.
- && attrs.surfaceInsets.left == 0
- && attrs.surfaceInsets.top == 0
- && attrs.surfaceInsets.right == 0
- && attrs.surfaceInsets.bottom == 0
- // Don't make surface opaque when resizing to reduce the amount of
- // artifacts shown in areas the app isn't drawing content to.
- && !w.isDragResizing()) {
- flags |= SurfaceControl.OPAQUE;
- }
-
- mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
- attrs.getTitle().toString(),
- width, height, format, flags, this);
-
- w.setHasSurface(true);
-
- if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
- Slog.i(TAG, " CREATE SURFACE "
- + mSurfaceController + " IN SESSION "
- + mSession.mSurfaceSession
- + ": pid=" + mSession.mPid + " format="
- + attrs.format + " flags=0x"
- + Integer.toHexString(flags)
- + " / " + this);
- }
- } catch (OutOfResourcesException e) {
- w.setHasSurface(false);
- Slog.w(TAG, "OutOfResourcesException creating surface");
- mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
- mDrawState = NO_SURFACE;
- return null;
- } catch (Exception e) {
- w.setHasSurface(false);
- Slog.e(TAG, "Exception creating surface", e);
- mDrawState = NO_SURFACE;
- return null;
- }
-
- if (WindowManagerService.localLOGV) {
- Slog.v(TAG, "Got surface: " + mSurfaceController
- + ", set left=" + w.mFrame.left + " top=" + w.mFrame.top
- + ", animLayer=" + mAnimLayer);
- }
-
- if (SHOW_LIGHT_TRANSACTIONS) {
- Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
- WindowManagerService.logSurface(w, "CREATE pos=("
- + w.mFrame.left + "," + w.mFrame.top + ") ("
- + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", false);
- }
-
- // Start a new transaction and apply position & offset.
- final int layerStack = w.getDisplayContent().getDisplay().getLayerStack();
- if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
- "POS " + mTmpSize.left + ", " + mTmpSize.top, false);
- mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack,
- mAnimLayer);
- mLastHidden = true;
-
- if (WindowManagerService.localLOGV) Slog.v(
- TAG, "Created surface " + this);
+ if (mSurfaceController != null) {
+ return mSurfaceController;
}
+
+ w.setHasSurface(false);
+
+ if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
+ "createSurface " + this + ": mDrawState=DRAW_PENDING");
+
+ mDrawState = DRAW_PENDING;
+ if (w.mAppToken != null) {
+ if (w.mAppToken.mAppAnimator.animation == null) {
+ w.mAppToken.allDrawn = false;
+ w.mAppToken.deferClearAllDrawn = false;
+ } else {
+ // Currently animating, persist current state of allDrawn until animation
+ // is complete.
+ w.mAppToken.deferClearAllDrawn = true;
+ }
+ }
+
+ mService.makeWindowFreezingScreenIfNeededLocked(w);
+
+ int flags = SurfaceControl.HIDDEN;
+ final WindowManager.LayoutParams attrs = w.mAttrs;
+
+ if (mService.isSecureLocked(w)) {
+ flags |= SurfaceControl.SECURE;
+ }
+
+ mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0);
+ calculateSurfaceBounds(w, attrs);
+ final int width = mTmpSize.width();
+ final int height = mTmpSize.height();
+
+ if (DEBUG_VISIBILITY) {
+ Slog.v(TAG, "Creating surface in session "
+ + mSession.mSurfaceSession + " window " + this
+ + " w=" + width + " h=" + height
+ + " x=" + mTmpSize.left + " y=" + mTmpSize.top
+ + " format=" + attrs.format + " flags=" + flags);
+ }
+
+ // We may abort, so initialize to defaults.
+ mLastSystemDecorRect.set(0, 0, 0, 0);
+ mHasClipRect = false;
+ mClipRect.set(0, 0, 0, 0);
+ mLastClipRect.set(0, 0, 0, 0);
+
+ // Set up surface control with initial size.
+ try {
+
+ final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
+ final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
+ if (!PixelFormat.formatHasAlpha(attrs.format)
+ // Don't make surface with surfaceInsets opaque as they display a
+ // translucent shadow.
+ && attrs.surfaceInsets.left == 0
+ && attrs.surfaceInsets.top == 0
+ && attrs.surfaceInsets.right == 0
+ && attrs.surfaceInsets.bottom == 0
+ // Don't make surface opaque when resizing to reduce the amount of
+ // artifacts shown in areas the app isn't drawing content to.
+ && !w.isDragResizing()) {
+ flags |= SurfaceControl.OPAQUE;
+ }
+
+ mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
+ attrs.getTitle().toString(),
+ width, height, format, flags, this);
+
+ w.setHasSurface(true);
+
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ Slog.i(TAG, " CREATE SURFACE "
+ + mSurfaceController + " IN SESSION "
+ + mSession.mSurfaceSession
+ + ": pid=" + mSession.mPid + " format="
+ + attrs.format + " flags=0x"
+ + Integer.toHexString(flags)
+ + " / " + this);
+ }
+ } catch (OutOfResourcesException e) {
+ Slog.w(TAG, "OutOfResourcesException creating surface");
+ mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
+ mDrawState = NO_SURFACE;
+ return null;
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception creating surface", e);
+ mDrawState = NO_SURFACE;
+ return null;
+ }
+
+ if (WindowManagerService.localLOGV) Slog.v(TAG, "Got surface: " + mSurfaceController
+ + ", set left=" + w.mFrame.left + " top=" + w.mFrame.top
+ + ", animLayer=" + mAnimLayer);
+
+ if (SHOW_LIGHT_TRANSACTIONS) {
+ Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
+ WindowManagerService.logSurface(w, "CREATE pos=("
+ + w.mFrame.left + "," + w.mFrame.top + ") ("
+ + width + "x" + height + "), layer=" + mAnimLayer + " HIDE", false);
+ }
+
+ // Start a new transaction and apply position & offset.
+ final int layerStack = w.getDisplayContent().getDisplay().getLayerStack();
+ if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+ "POS " + mTmpSize.left + ", " + mTmpSize.top, false);
+ mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, mAnimLayer);
+ mLastHidden = true;
+
+ if (WindowManagerService.localLOGV) Slog.v(TAG, "Created surface " + this);
return mSurfaceController;
}
@@ -776,59 +781,59 @@
mWin.mSurfaceSaved = false;
- if (mSurfaceController != null) {
- int i = mWin.mChildWindows.size();
- // When destroying a surface we want to make sure child windows
- // are hidden. If we are preserving the surface until redraw though
- // we intend to swap it out with another surface for resizing. In this case
- // the window always remains visible to the user and the child windows
- // should likewise remain visable.
- while (!mDestroyPreservedSurfaceUponRedraw && i > 0) {
- i--;
- WindowState c = mWin.mChildWindows.get(i);
- c.mAttachedHidden = true;
- }
-
- try {
- if (DEBUG_VISIBILITY) logWithStack(TAG, "Window " + this + " destroying surface "
- + mSurfaceController + ", session " + mSession);
- if (mSurfaceDestroyDeferred) {
- if (mSurfaceController != null && mPendingDestroySurface != mSurfaceController) {
- if (mPendingDestroySurface != null) {
- if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
- WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
- }
- mPendingDestroySurface.destroyInTransaction();
- }
- mPendingDestroySurface = mSurfaceController;
- }
- } else {
- if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
- WindowManagerService.logSurface(mWin, "DESTROY", true);
- }
- destroySurface();
- }
- // Don't hide wallpaper if we're deferring the surface destroy
- // because of a surface change.
- if (!(mSurfaceDestroyDeferred && mDestroyPreservedSurfaceUponRedraw)) {
- mWallpaperControllerLocked.hideWallpapers(mWin);
- }
- } catch (RuntimeException e) {
- Slog.w(TAG, "Exception thrown when destroying Window " + this
- + " surface " + mSurfaceController + " session " + mSession
- + ": " + e.toString());
- }
-
- // Whether the surface was preserved (and copied to mPendingDestroySurface) or not, it
- // needs to be cleared to match the WindowState.mHasSurface state. It is also necessary
- // so it can be recreated successfully in mPendingDestroySurface case.
- mWin.setHasSurface(false);
- if (mSurfaceController != null) {
- mSurfaceController.setShown(false);
- }
- mSurfaceController = null;
- mDrawState = NO_SURFACE;
+ if (mSurfaceController == null) {
+ return;
}
+
+ int i = mWin.mChildWindows.size();
+ // When destroying a surface we want to make sure child windows are hidden. If we are
+ // preserving the surface until redraw though we intend to swap it out with another surface
+ // for resizing. In this case the window always remains visible to the user and the child
+ // windows should likewise remain visible.
+ while (!mDestroyPreservedSurfaceUponRedraw && i > 0) {
+ i--;
+ WindowState c = mWin.mChildWindows.get(i);
+ c.mAttachedHidden = true;
+ }
+
+ try {
+ if (DEBUG_VISIBILITY) logWithStack(TAG, "Window " + this + " destroying surface "
+ + mSurfaceController + ", session " + mSession);
+ if (mSurfaceDestroyDeferred) {
+ if (mSurfaceController != null && mPendingDestroySurface != mSurfaceController) {
+ if (mPendingDestroySurface != null) {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
+ }
+ mPendingDestroySurface.destroyInTransaction();
+ }
+ mPendingDestroySurface = mSurfaceController;
+ }
+ } else {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ WindowManagerService.logSurface(mWin, "DESTROY", true);
+ }
+ destroySurface();
+ }
+ // Don't hide wallpaper if we're deferring the surface destroy
+ // because of a surface change.
+ if (!mDestroyPreservedSurfaceUponRedraw) {
+ mWallpaperControllerLocked.hideWallpapers(mWin);
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Exception thrown when destroying Window " + this
+ + " surface " + mSurfaceController + " session " + mSession + ": " + e.toString());
+ }
+
+ // Whether the surface was preserved (and copied to mPendingDestroySurface) or not, it
+ // needs to be cleared to match the WindowState.mHasSurface state. It is also necessary
+ // so it can be recreated successfully in mPendingDestroySurface case.
+ mWin.setHasSurface(false);
+ if (mSurfaceController != null) {
+ mSurfaceController.setShown(false);
+ }
+ mSurfaceController = null;
+ mDrawState = NO_SURFACE;
}
void destroyDeferredSurfaceLocked() {
@@ -1328,6 +1333,9 @@
if (prepared && mLastHidden && mDrawState == HAS_DRAWN) {
if (showSurfaceRobustlyLocked()) {
+ if (mDestroyPreservedSurfaceUponRedraw) {
+ mService.mDestroyPreservedSurface.add(mWin);
+ }
mAnimator.requestRemovalOfReplacedWindows(w);
mLastHidden = false;
if (mIsWallpaper) {
@@ -1736,8 +1744,18 @@
}
void destroySurface() {
- mSurfaceController.destroyInTransaction();
- mSurfaceController = null;
+ try {
+ if (mSurfaceController != null) {
+ mSurfaceController.destroyInTransaction();
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Exception thrown when destroying surface " + this
+ + " surface " + mSurfaceController + " session " + mSession + ": " + e);
+ } finally {
+ mWin.setHasSurface(false);
+ mSurfaceController = null;
+ mDrawState = NO_SURFACE;
+ }
}
void setMoveAnimation(int left, int top) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 3219bfe..93164de 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
@@ -133,11 +134,14 @@
Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(4));
// }
try {
- mSurfaceControl.destroy();
- mSurfaceShown = false;
- mSurfaceControl = null;
+ if (mSurfaceControl != null) {
+ mSurfaceControl.destroy();
+ }
} catch (RuntimeException e) {
Slog.w(TAG, "Error destroying surface in: " + this, e);
+ } finally {
+ mSurfaceShown = false;
+ mSurfaceControl = null;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 4e1b644..f705df8 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -7,7 +7,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -676,8 +675,10 @@
// currently animating... let's do something.
final int left = w.mFrame.left;
final int top = w.mFrame.top;
+ final boolean adjustedForMinimizedDockedStack = w.getTask() != null &&
+ w.getTask().mStack.isAdjustedForMinimizedDockedStack();
if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
- && !w.isDragResizing()) {
+ && !w.isDragResizing() && !adjustedForMinimizedDockedStack) {
winAnimator.setMoveAnimation(left, top);
}
@@ -751,7 +752,7 @@
}
if ((w.isOnScreenIgnoringKeyguard()
|| winAnimator.mAttrType == TYPE_BASE_APPLICATION)
- && !w.mExiting && !w.mDestroying) {
+ && !w.mAnimatingExit && !w.mDestroying) {
if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
Slog.v(TAG, "Eval win " + w + ": isDrawn="
+ w.isDrawnLw()
@@ -1099,6 +1100,7 @@
processApplicationsAnimatingInPlace(transit);
+ mTmpLayerAndToken.token = null;
handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken);
final AppWindowToken topClosingApp = mTmpLayerAndToken.token;
final int topClosingLayer = mTmpLayerAndToken.layer;
@@ -1111,7 +1113,8 @@
final AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
topClosingApp.mAppAnimator;
- mService.mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
+ mService.mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator,
+ mService.mOpeningApps, mService.mClosingApps);
mService.mAppTransition.postAnimationCallback();
mService.mAppTransition.clear();
@@ -1181,17 +1184,17 @@
int layer = -1;
for (int j = 0; j < wtoken.windows.size(); j++) {
final WindowState win = wtoken.windows.get(j);
- // Clearing the mExiting flag before entering animation. It will be set to true
+ // Clearing the mAnimatingExit flag before entering animation. It will be set to true
// if app window is removed, or window relayout to invisible. We don't want to
// clear it out for windows that get replaced, because the animation depends on
// the flag to remove the replaced window.
//
- // We also don't clear the mExiting flag for windows which have the
+ // We also don't clear the mAnimatingExit flag for windows which have the
// mRemoveOnExit flag. This indicates an explicit remove request has been issued
// by the client. We should let animation proceed and not clear this flag or
// they won't eventually be removed by WindowStateAnimator#finishExit.
if (!win.mWillReplaceWindow && !win.mRemoveOnExit) {
- win.mExiting = false;
+ win.mAnimatingExit = false;
}
if (win.mWinAnimator.mAnimLayer > layer) {
layer = win.mWinAnimator.mAnimLayer;
@@ -1230,7 +1233,7 @@
wtoken.deferClearAllDrawn = false;
// Ensure that apps that are mid-starting are also scheduled to have their
// starting windows removed after the animation is complete
- if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
+ if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
mService.scheduleRemoveStartingWindowLocked(wtoken);
}
mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
diff --git a/core/java/android/view/animation/ClipRectLRAnimation.java b/services/core/java/com/android/server/wm/animation/ClipRectLRAnimation.java
similarity index 87%
rename from core/java/android/view/animation/ClipRectLRAnimation.java
rename to services/core/java/com/android/server/wm/animation/ClipRectLRAnimation.java
index 8993cd3..0db4c70 100644
--- a/core/java/android/view/animation/ClipRectLRAnimation.java
+++ b/services/core/java/com/android/server/wm/animation/ClipRectLRAnimation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,12 +11,14 @@
* 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.
+ * limitations under the License
*/
-package android.view.animation;
+package com.android.server.wm.animation;
import android.graphics.Rect;
+import android.view.animation.ClipRectAnimation;
+import android.view.animation.Transformation;
/**
* Special case of ClipRectAnimation that animates only the left/right
diff --git a/services/core/java/com/android/server/wm/animation/ClipRectTBAnimation.java b/services/core/java/com/android/server/wm/animation/ClipRectTBAnimation.java
new file mode 100644
index 0000000..1f5b1a3
--- /dev/null
+++ b/services/core/java/com/android/server/wm/animation/ClipRectTBAnimation.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm.animation;
+
+import android.graphics.Rect;
+import android.view.animation.ClipRectAnimation;
+import android.view.animation.Interpolator;
+import android.view.animation.Transformation;
+import android.view.animation.TranslateAnimation;
+
+/**
+ * Special case of ClipRectAnimation that animates only the top/bottom
+ * dimensions of the clip, picking up the other dimensions from whatever is
+ * set on the transform already. In addition to that, information about a vertical translation
+ * animation can be specified so this animation simulates as the clip would be applied after instead
+ * of before applying the translation.
+ */
+public class ClipRectTBAnimation extends ClipRectAnimation {
+
+ private final int mFromTranslateY;
+ private final int mToTranslateY;
+ private final Interpolator mTranslateInterpolator;
+ private float mNormalizedTime;
+
+ /**
+ * Constructor. Passes in 0 for Left/Right parameters of ClipRectAnimation
+ */
+ public ClipRectTBAnimation(int fromT, int fromB, int toT, int toB,
+ int fromTranslateY, int toTranslateY, Interpolator translateInterpolator) {
+ super(0, fromT, 0, fromB, 0, toT, 0, toB);
+ mFromTranslateY = fromTranslateY;
+ mToTranslateY = toTranslateY;
+ mTranslateInterpolator = translateInterpolator;
+ }
+
+ @Override
+ public boolean getTransformation(long currentTime, Transformation outTransformation) {
+
+ // Hack: Because translation animation has a different interpolator, we need to duplicate
+ // code from Animation here and use it to calculate/store the uninterpolated normalized
+ // time.
+ final long startOffset = getStartOffset();
+ final long duration = getDuration();
+ float normalizedTime;
+ if (duration != 0) {
+ normalizedTime = ((float) (currentTime - (getStartTime() + startOffset))) /
+ (float) duration;
+ } else {
+ // time is a step-change with a zero duration
+ normalizedTime = currentTime < getStartTime() ? 0.0f : 1.0f;
+ }
+ mNormalizedTime = normalizedTime;
+ return super.getTransformation(currentTime, outTransformation);
+ }
+
+ /**
+ * Calculates and sets clip rect on given transformation. It uses existing values
+ * on the Transformation for Left/Right clip parameters.
+ */
+ @Override
+ protected void applyTransformation(float it, Transformation tr) {
+ float translationT = mTranslateInterpolator.getInterpolation(mNormalizedTime);
+ int translation =
+ (int) (mFromTranslateY + (mToTranslateY - mFromTranslateY) * translationT);
+ Rect oldClipRect = tr.getClipRect();
+ tr.setClipRect(oldClipRect.left,
+ mFromRect.top - translation + (int) ((mToRect.top - mFromRect.top) * it),
+ oldClipRect.right,
+ mFromRect.bottom - translation + (int) ((mToRect.bottom - mFromRect.bottom) * it));
+ }
+
+}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index bb571c3..5e5c6d9 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -17,6 +17,7 @@
$(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
$(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_HardwarePropertiesManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
diff --git a/core/jni/android_os_HardwarePropertiesManager.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
similarity index 93%
rename from core/jni/android_os_HardwarePropertiesManager.cpp
rename to services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index dc1ba48..214d988 100644
--- a/core/jni/android_os_HardwarePropertiesManager.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "HardwarePropertiesManager-JNI"
+#define LOG_TAG "HardwarePropertiesManagerService-JNI"
#include "JNIHelp.h"
#include "jni.h"
@@ -137,7 +137,7 @@
// ----------------------------------------------------------------------------
-static const JNINativeMethod gHardwarePropertiesManagerMethods[] = {
+static const JNINativeMethod gHardwarePropertiesManagerServiceMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "()V",
(void*) nativeInit },
@@ -149,11 +149,11 @@
(void*) nativeGetCpuUsages }
};
-int register_android_os_HardwarePropertiesManager(JNIEnv* env) {
+int register_android_server_HardwarePropertiesManagerService(JNIEnv* env) {
gHardwarePropertiesModule = nullptr;
- int res = jniRegisterNativeMethods(env, "android/os/HardwarePropertiesManager",
- gHardwarePropertiesManagerMethods,
- NELEM(gHardwarePropertiesManagerMethods));
+ int res = jniRegisterNativeMethods(env, "com/android/server/HardwarePropertiesManagerService",
+ gHardwarePropertiesManagerServiceMethods,
+ NELEM(gHardwarePropertiesManagerServiceMethods));
jclass clazz = env->FindClass("android/os/CpuUsageInfo");
gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index cdd5519..e39445a 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -42,7 +42,7 @@
static jmethodID method_reportAGpsStatus;
static jmethodID method_reportNmea;
static jmethodID method_setEngineCapabilities;
-static jmethodID method_setGpsYearOfHardware;
+static jmethodID method_setGnssYearOfHardware;
static jmethodID method_xtraDownloadRequest;
static jmethodID method_reportNiNotification;
static jmethodID method_requestRefLocation;
@@ -133,11 +133,10 @@
for (size_t i = 0; i < sGnssSvListSize; i++) {
GnssSvInfo& info = sGnssSvList[i];
info.svid = sv_status->sv_list[i].prn;
- // TODO: implement the correct logic to derive the constellation type
- // based on PRN ranges.
if (info.svid >=1 && info.svid <= 32) {
info.constellation = GNSS_CONSTELLATION_GPS;
} else {
+ ALOGD("Unknown constellation type with Svid = %d.", info.svid);
info.constellation = GNSS_CONSTELLATION_UNKNOWN;
}
info.snr = sv_status->sv_list[i].snr;
@@ -198,10 +197,10 @@
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
-static void set_system_info_callback(const GpsSystemInfo* info) {
+static void set_system_info_callback(const GnssSystemInfo* info) {
ALOGD("set_system_info_callback: year_of_hw=%d\n", info->year_of_hw);
JNIEnv* env = AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(mCallbacksObj, method_setGpsYearOfHardware,
+ env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware,
info->year_of_hw);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
@@ -536,7 +535,7 @@
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
- method_setGpsYearOfHardware = env->GetMethodID(clazz, "setGpsYearOfHardware", "(I)V");
+ method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
"(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
@@ -1074,7 +1073,9 @@
template<>
const char *const JavaMethodHelper<uint16_t>::signature_ = "(S)V";
template<>
-const char *const JavaMethodHelper<int>::signature_ = "(I)V";
+const char *const JavaMethodHelper<int32_t>::signature_ = "(I)V";
+template<>
+const char *const JavaMethodHelper<uint32_t>::signature_ = "(I)V";
template<>
const char *const JavaMethodHelper<int64_t>::signature_ = "(J)V";
template<>
@@ -1092,36 +1093,22 @@
JavaObject object(env, "android/location/GnssClock");
GpsClockFlags flags = clock->flags;
- SET_IF(GPS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+ SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
SET(Type, clock->type);
SET(TimeInNs, clock->time_ns);
- SET_IF(GPS_CLOCK_HAS_TIME_UNCERTAINTY,
+ SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
TimeUncertaintyInNs,
clock->time_uncertainty_ns);
- SET_IF(GPS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
- SET_IF(GPS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
- SET_IF(GPS_CLOCK_HAS_BIAS_UNCERTAINTY,
+ SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
BiasUncertaintyInNs,
clock->bias_uncertainty_ns);
- SET_IF(GPS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
- SET_IF(GPS_CLOCK_HAS_DRIFT_UNCERTAINTY,
+ SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+ SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
DriftUncertaintyInNsPerSec,
clock->drift_uncertainty_nsps);
- /*
- if (flags & GPS_CLOCK_TYPE_LOCAL_HW_TIME) {
- if (size == sizeof(GnssClock)) {
- jmethodID setterMethod =
- env->GetMethodID(gpsClockClass,
- "setTimeOfLastHwClockDiscontinuityInNs",
- longSignature);
- env->CallVoidMethod(gpsClockObject,
- setterMethod,
- reinterpret_cast<GnssClock*>(clock)->time_of_last_hw_clock_discontinuity_ns);
- }
- }
- */
-
return object.get();
}
@@ -1129,25 +1116,23 @@
JavaObject object(env, "android/location/GnssClock");
GpsClockFlags flags = clock->flags;
- SET_IF(GPS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
- SET(Type, clock->type);
+ SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+ SET(Type, static_cast<uint8_t>(GPS_CLOCK_TYPE_LOCAL_HW_TIME));
SET(TimeInNs, clock->time_ns);
- SET_IF(GPS_CLOCK_HAS_TIME_UNCERTAINTY,
+ SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
TimeUncertaintyInNs,
clock->time_uncertainty_ns);
- SET_IF(GPS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
- SET_IF(GPS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
- SET_IF(GPS_CLOCK_HAS_BIAS_UNCERTAINTY,
+ SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+ SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
BiasUncertaintyInNs,
clock->bias_uncertainty_ns);
- SET_IF(GPS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
- SET_IF(GPS_CLOCK_HAS_DRIFT_UNCERTAINTY,
+ SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+ SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
DriftUncertaintyInNsPerSec,
clock->drift_uncertainty_nsps);
- SET_IF(GPS_CLOCK_TYPE_LOCAL_HW_TIME,
- TimeOfLastHwClockDiscontinuityInNs,
- clock->time_of_last_hw_clock_discontinuity_ns);
+ SET(HardwareClockDiscontinuityCount, clock->hw_clock_discontinuity_count);
return object.get();
}
@@ -1156,12 +1141,18 @@
GpsMeasurement* measurement) {
JavaObject object(env, "android/location/GnssMeasurement");
GpsMeasurementFlags flags = measurement->flags;
-
SET(Svid, static_cast<int16_t>(measurement->prn));
+ if (measurement->prn >= 1 || measurement->prn <= 32) {
+ SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+ } else {
+ ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
+ SET(ConstellationType,
+ static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
+ }
SET(TimeOffsetInNs, measurement->time_offset_ns);
SET(State, measurement->state);
- SET(ReceivedGpsTowInNs, measurement->received_gps_tow_ns);
- SET(ReceivedGpsTowUncertaintyInNs,
+ SET(ReceivedSvTimeInNs, measurement->received_gps_tow_ns);
+ SET(ReceivedSvTimeUncertaintyInNs,
measurement->received_gps_tow_uncertainty_ns);
SET(Cn0InDbHz, measurement->c_n0_dbhz);
SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
@@ -1171,57 +1162,57 @@
SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
SET(AccumulatedDeltaRangeUncertaintyInMeters,
measurement->accumulated_delta_range_uncertainty_m);
- SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE,
+ SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
PseudorangeInMeters,
measurement->pseudorange_m);
- SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
PseudorangeUncertaintyInMeters,
measurement->pseudorange_uncertainty_m);
- SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE,
+ SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
CodePhaseInChips,
measurement->code_phase_chips);
- SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
CodePhaseUncertaintyInChips,
measurement->code_phase_uncertainty_chips);
- SET_IF(GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
CarrierFrequencyInHz,
measurement->carrier_frequency_hz);
- SET_IF(GPS_MEASUREMENT_HAS_CARRIER_CYCLES,
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
CarrierCycles,
measurement->carrier_cycles);
- SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE,
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE,
CarrierPhase,
measurement->carrier_phase);
- SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
CarrierPhaseUncertainty,
measurement->carrier_phase_uncertainty);
SET(LossOfLock, measurement->loss_of_lock);
- SET_IF(GPS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
- SET_IF(GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
+ SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
+ SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
TimeFromLastBitInMs,
measurement->time_from_last_bit_ms);
- SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT,
+ SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
DopplerShiftInHz,
measurement->doppler_shift_hz);
- SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
DopplerShiftUncertaintyInHz,
measurement->doppler_shift_uncertainty_hz);
SET(MultipathIndicator, measurement->multipath_indicator);
- SET_IF(GPS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
- SET_IF(GPS_MEASUREMENT_HAS_ELEVATION,
+ SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+ SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
ElevationInDeg,
measurement->elevation_deg);
- SET_IF(GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
ElevationUncertaintyInDeg,
measurement->elevation_uncertainty_deg);
- SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH,
+ SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
AzimuthInDeg,
measurement->azimuth_deg);
- SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
AzimuthUncertaintyInDeg,
measurement->azimuth_uncertainty_deg);
SET(UsedInFix,
- (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
+ (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
return object.get();
}
@@ -1232,11 +1223,12 @@
GpsMeasurementFlags flags = measurement->flags;
SET(Svid, measurement->svid);
+ SET(ConstellationType, measurement->constellation);
SET(TimeOffsetInNs, measurement->time_offset_ns);
SET(State, measurement->state);
- SET(ReceivedGpsTowInNs, measurement->received_gps_tow_ns);
- SET(ReceivedGpsTowUncertaintyInNs,
- measurement->received_gps_tow_uncertainty_ns);
+ SET(ReceivedSvTimeInNs, measurement->received_sv_time_in_ns);
+ SET(ReceivedSvTimeUncertaintyInNs,
+ measurement->received_sv_time_uncertainty_in_ns);
SET(Cn0InDbHz, measurement->c_n0_dbhz);
SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
SET(PseudorangeRateUncertaintyInMetersPerSec,
@@ -1245,62 +1237,56 @@
SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
SET(AccumulatedDeltaRangeUncertaintyInMeters,
measurement->accumulated_delta_range_uncertainty_m);
- SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE,
+ SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
PseudorangeInMeters,
measurement->pseudorange_m);
- SET_IF(GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
PseudorangeUncertaintyInMeters,
measurement->pseudorange_uncertainty_m);
- SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE,
+ SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
CodePhaseInChips,
measurement->code_phase_chips);
- SET_IF(GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
CodePhaseUncertaintyInChips,
measurement->code_phase_uncertainty_chips);
- SET_IF(GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
CarrierFrequencyInHz,
measurement->carrier_frequency_hz);
- SET_IF(GPS_MEASUREMENT_HAS_CARRIER_CYCLES,
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
CarrierCycles,
measurement->carrier_cycles);
- SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE,
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE,
CarrierPhase,
measurement->carrier_phase);
- SET_IF(GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
CarrierPhaseUncertainty,
measurement->carrier_phase_uncertainty);
- SET(LossOfLock, measurement->loss_of_lock);
- SET_IF(GPS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
- SET_IF(GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
+ SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
+ SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
TimeFromLastBitInMs,
measurement->time_from_last_bit_ms);
- SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT,
+ SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
DopplerShiftInHz,
measurement->doppler_shift_hz);
- SET_IF(GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
DopplerShiftUncertaintyInHz,
measurement->doppler_shift_uncertainty_hz);
SET(MultipathIndicator, measurement->multipath_indicator);
- SET_IF(GPS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
- SET_IF(GPS_MEASUREMENT_HAS_ELEVATION,
+ SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
+ SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
ElevationInDeg,
measurement->elevation_deg);
- SET_IF(GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
ElevationUncertaintyInDeg,
measurement->elevation_uncertainty_deg);
- SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH,
+ SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
AzimuthInDeg,
measurement->azimuth_deg);
- SET_IF(GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
+ SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
AzimuthUncertaintyInDeg,
measurement->azimuth_uncertainty_deg);
SET(UsedInFix,
- (flags & GPS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
-
- SET(PseudorangeRateCarrierInMetersPerSec,
- measurement->pseudorange_rate_carrier_mps);
- SET(PseudorangeRateCarrierUncertaintyInMetersPerSec,
- measurement->pseudorange_rate_carrier_uncertainty_mps);
+ (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
return object.get();
}
@@ -1480,8 +1466,18 @@
return NULL;
}
JavaObject object(env, "android/location/GnssNavigationMessage");
- SET(Type, message->type);
SET(Svid, static_cast<int16_t>(message->prn));
+ if (message->prn >=1 && message->prn <= 32) {
+ SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+ // Legacy driver doesn't set the higher byte to constellation type
+ // correctly. Set the higher byte to 'GPS'.
+ SET(Type, static_cast<int16_t>(message->type | 0x0100));
+ } else {
+ ALOGD("Unknown constellation type with Svid = %d.", message->prn);
+ SET(ConstellationType,
+ static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
+ SET(Type, static_cast<int16_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
+ }
SET(MessageId, message->message_id);
SET(SubmessageId, message->submessage_id);
object.callSetter("setData", data, dataLength);
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index ef5c56c..be99673 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -44,6 +44,7 @@
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
int register_android_server_Watchdog(JNIEnv* env);
+int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
};
using namespace android;
@@ -83,6 +84,7 @@
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
register_android_server_Watchdog(env);
+ register_android_server_HardwarePropertiesManagerService(env);
return JNI_VERSION_1_4;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 79d2307..33225eb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1689,7 +1689,7 @@
final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
migrateUserRestrictionsForUser(UserHandle.SYSTEM, deviceOwnerAdmin,
- /* exceptionList =*/ null);
+ /* exceptionList =*/ null, /* isDeviceOwner =*/ true);
// Push DO user restrictions to user manager.
pushUserRestrictions(UserHandle.USER_SYSTEM);
@@ -1697,39 +1697,36 @@
mOwners.setDeviceOwnerUserRestrictionsMigrated();
}
- // Migrate for POs. We have a few more exceptions.
- final Set<String> normalExceptionList = Sets.newArraySet(
+ // Migrate for POs.
+
+ // The following restrictions can be set on secondary users by the device owner, so we
+ // assume they're not from the PO.
+ final Set<String> secondaryUserExceptionList = Sets.newArraySet(
UserManager.DISALLOW_OUTGOING_CALLS,
UserManager.DISALLOW_SMS);
- final Set<String> managedExceptionList = new ArraySet<>(normalExceptionList.size() + 1);
- managedExceptionList.addAll(normalExceptionList);
- managedExceptionList.add(UserManager.DISALLOW_WALLPAPER);
-
for (UserInfo ui : mUserManager.getUsers()) {
final int userId = ui.id;
if (mOwners.getProfileOwnerUserRestrictionsNeedsMigration(userId)) {
- if (userId != UserHandle.USER_SYSTEM) {
- if (VERBOSE_LOG) {
- Log.v(LOG_TAG, "Migrating PO user restrictions for user " + userId);
- }
- migrated = true;
-
- final ActiveAdmin profileOwnerAdmin = getProfileOwnerAdminLocked(userId);
-
- final Set<String> exceptionList =
- ui.isManagedProfile() ? managedExceptionList : normalExceptionList;
-
- migrateUserRestrictionsForUser(ui.getUserHandle(), profileOwnerAdmin,
- exceptionList);
-
- // Note if a secondary user has no PO but has a DA that disables camera, we
- // don't get here and won't push the camera user restriction to UserManager
- // here. That's okay because we'll push user restrictions anyway when a user
- // starts. But we still do it because we want to let user manager persist
- // upon migration.
- pushUserRestrictions(userId);
+ if (VERBOSE_LOG) {
+ Log.v(LOG_TAG, "Migrating PO user restrictions for user " + userId);
}
+ migrated = true;
+
+ final ActiveAdmin profileOwnerAdmin = getProfileOwnerAdminLocked(userId);
+
+ final Set<String> exceptionList =
+ (userId == UserHandle.USER_SYSTEM) ? null : secondaryUserExceptionList;
+
+ migrateUserRestrictionsForUser(ui.getUserHandle(), profileOwnerAdmin,
+ exceptionList, /* isDeviceOwner =*/ false);
+
+ // Note if a secondary user has no PO but has a DA that disables camera, we
+ // don't get here and won't push the camera user restriction to UserManager
+ // here. That's okay because we'll push user restrictions anyway when a user
+ // starts. But we still do it because we want to let user manager persist
+ // upon migration.
+ pushUserRestrictions(userId);
mOwners.setProfileOwnerUserRestrictionsMigrated(userId);
}
@@ -1740,7 +1737,7 @@
}
private void migrateUserRestrictionsForUser(UserHandle user, ActiveAdmin admin,
- Set<String> exceptionList) {
+ Set<String> exceptionList, boolean isDeviceOwner) {
final Bundle origRestrictions = mUserManagerInternal.getBaseUserRestrictions(
user.getIdentifier());
@@ -1751,7 +1748,11 @@
if (!origRestrictions.getBoolean(key)) {
continue;
}
- if (exceptionList!= null && exceptionList.contains(key)) {
+ final boolean canOwnerChange = isDeviceOwner
+ ? UserRestrictionsUtils.canDeviceOwnerChange(key)
+ : UserRestrictionsUtils.canProfileOwnerChange(key, user.getIdentifier());
+
+ if (!canOwnerChange || (exceptionList!= null && exceptionList.contains(key))) {
newBaseRestrictions.putBoolean(key, true);
} else {
newOwnerRestrictions.putBoolean(key, true);
@@ -3874,7 +3875,7 @@
// challenge only and keep the screen on. However there is no easy way of doing that at the
// moment so we set the screen off timeout regardless of whether it affects the parent user
// or the profile challenge only.
- long timeMs = Integer.MAX_VALUE;
+ long timeMs = Long.MAX_VALUE;
List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
for (UserInfo userInfo : profiles) {
DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
@@ -3898,15 +3899,14 @@
final long ident = mInjector.binderClearCallingIdentity();
try {
- if (policy.mLastMaximumTimeToLock != Integer.MAX_VALUE) {
+ if (policy.mLastMaximumTimeToLock != Long.MAX_VALUE) {
// Make sure KEEP_SCREEN_ON is disabled, since that
// would allow bypassing of the maximum time to lock.
mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
}
- // TODO It can overflow. Cap it.
- mInjector.getPowerManagerInternal()
- .setMaximumScreenOffTimeoutFromDeviceAdmin((int)policy.mLastMaximumTimeToLock);
+ mInjector.getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(
+ (int) Math.min(policy.mLastMaximumTimeToLock, Integer.MAX_VALUE));
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
@@ -4968,6 +4968,11 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
+ // Allow setting this policy to true only if there is a split system user.
+ if (forceEphemeralUsers && !mInjector.userManagerIsSplitSystemUser()) {
+ throw new IllegalArgumentException(
+ "Cannot force ephemeral users on systems without split system user.");
+ }
boolean removeAllUsers = false;
synchronized (this) {
final ActiveAdmin deviceOwner =
@@ -5396,6 +5401,9 @@
}
synchronized (this) {
enforceCanSetDeviceOwnerLocked(userId);
+ if (getActiveAdminUncheckedLocked(admin, userId) == null) {
+ throw new IllegalArgumentException("Not active admin: " + admin);
+ }
// Shutting down backup manager service permanently.
long ident = mInjector.binderClearCallingIdentity();
@@ -5571,6 +5579,11 @@
}
synchronized (this) {
enforceCanSetProfileOwnerLocked(userHandle);
+
+ if (getActiveAdminUncheckedLocked(who, userHandle) == null) {
+ throw new IllegalArgumentException("Not active admin: " + who);
+ }
+
mOwners.setProfileOwner(who, ownerName, userHandle);
mOwners.writeProfileOwner(userHandle);
return true;
@@ -6810,6 +6823,11 @@
if (!mInjector.binderGetCallingUserHandle().isSystem()) {
throw new SecurityException("createAndManageUser was called from non-system user");
}
+ if (!mInjector.userManagerIsSplitSystemUser()
+ && (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0) {
+ throw new IllegalArgumentException(
+ "Ephemeral users are only supported on systems with a split system user.");
+ }
// Create user.
UserHandle user = null;
synchronized (this) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0cf9328..c854573 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -488,6 +488,7 @@
MmsServiceBroker mmsService = null;
EntropyMixer entropyMixer = null;
VrManagerService vrManagerService = null;
+ HardwarePropertiesManagerService hardwarePropertiesService = null;
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -760,7 +761,7 @@
traceBeginAndSlog("StartNetworkStatsService");
try {
- networkStats = new NetworkStatsService(context, networkManagement, alarm);
+ networkStats = NetworkStatsService.create(context, networkManagement);
ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
} catch (Throwable e) {
reportWtf("starting NetworkStats Service", e);
@@ -962,6 +963,17 @@
Slog.e(TAG, "Failure starting SerialService", e);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
+ "StartHardwarePropertiesManagerService");
+ try {
+ hardwarePropertiesService = new HardwarePropertiesManagerService(context);
+ ServiceManager.addService(Context.HARDWARE_PROPERTIES_SERVICE,
+ hardwarePropertiesService);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting HardwarePropertiesManagerService", e);
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
mSystemServiceManager.startService(TwilightService.class);
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 5229b40..4f99bff 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -19,6 +19,7 @@
import com.android.internal.util.HexDump;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
+import com.android.internal.util.MessageUtils;
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
@@ -32,7 +33,6 @@
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Message;
-import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -40,16 +40,15 @@
import android.system.Os;
import android.system.PacketSocketAddress;
import android.util.Log;
+import android.util.SparseArray;
import android.util.TimeUtils;
import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.Thread;
import java.net.Inet4Address;
-import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
-import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Random;
@@ -131,6 +130,11 @@
private static final int CMD_TIMEOUT = PRIVATE_BASE + 3;
private static final int CMD_ONESHOT_TIMEOUT = PRIVATE_BASE + 4;
+ // For message logging.
+ private static final Class[] sMessageClasses = { DhcpClient.class };
+ private static final SparseArray<String> sMessageNames =
+ MessageUtils.findMessageNames(sMessageClasses);
+
// DHCP parameters that we request.
private static final byte[] REQUESTED_PARAMS = new byte[] {
DHCP_SUBNET_MASK,
@@ -460,30 +464,7 @@
}
private String messageName(int what) {
- switch (what) {
- case CMD_START_DHCP:
- return "CMD_START_DHCP";
- case CMD_STOP_DHCP:
- return "CMD_STOP_DHCP";
- case CMD_RENEW_DHCP:
- return "CMD_RENEW_DHCP";
- case CMD_PRE_DHCP_ACTION:
- return "CMD_PRE_DHCP_ACTION";
- case CMD_PRE_DHCP_ACTION_COMPLETE:
- return "CMD_PRE_DHCP_ACTION_COMPLETE";
- case CMD_POST_DHCP_ACTION:
- return "CMD_POST_DHCP_ACTION";
- case CMD_KICK:
- return "CMD_KICK";
- case CMD_RECEIVED_PACKET:
- return "CMD_RECEIVED_PACKET";
- case CMD_TIMEOUT:
- return "CMD_TIMEOUT";
- case CMD_ONESHOT_TIMEOUT:
- return "CMD_ONESHOT_TIMEOUT";
- default:
- return Integer.toString(what);
- }
+ return sMessageNames.get(what, Integer.toString(what));
}
private String messageToString(Message message) {
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index d0d87b1..2a90c60 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -16,12 +16,15 @@
package android.net.ip;
+import com.android.internal.util.MessageUtils;
+
import android.content.Context;
import android.net.DhcpResults;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.LinkProperties.ProvisioningChange;
+import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.dhcp.DhcpClient;
@@ -29,7 +32,9 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -61,6 +66,14 @@
private static final boolean DBG = true;
private static final boolean VDBG = false;
+ private static final boolean NO_CALLBACKS = false;
+ private static final boolean SEND_CALLBACKS = true;
+
+ // For message logging.
+ private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class };
+ private static final SparseArray<String> sWhatToString =
+ MessageUtils.findMessageNames(sMessageClasses);
+
/**
* Callbacks for handling IpManager events.
*/
@@ -96,6 +109,35 @@
public void onQuit() {}
}
+ public static class WaitForProvisioningCallback extends Callback {
+ private LinkProperties mCallbackLinkProperties;
+
+ public LinkProperties waitForProvisioning() {
+ synchronized (this) {
+ try {
+ wait();
+ } catch (InterruptedException e) {}
+ return mCallbackLinkProperties;
+ }
+ }
+
+ @Override
+ public void onProvisioningSuccess(LinkProperties newLp) {
+ synchronized (this) {
+ mCallbackLinkProperties = newLp;
+ notify();
+ }
+ }
+
+ @Override
+ public void onProvisioningFailure(LinkProperties newLp) {
+ synchronized (this) {
+ mCallbackLinkProperties = null;
+ notify();
+ }
+ }
+ }
+
/**
* This class encapsulates parameters to be passed to
* IpManager#startProvisioning(). A defensive copy is made by IpManager
@@ -160,6 +202,8 @@
private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 4;
// Sent by NetlinkTracker to communicate netlink events.
private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
+ private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6;
+ private static final int CMD_UPDATE_HTTP_PROXY = 7;
private static final int MAX_LOG_RECORDS = 1000;
@@ -181,10 +225,12 @@
/**
* Non-final member variables accessed only from within our StateMachine.
*/
+ private ProvisioningConfiguration mConfiguration;
private IpReachabilityMonitor mIpReachabilityMonitor;
private DhcpClient mDhcpClient;
private DhcpResults mDhcpResults;
- private ProvisioningConfiguration mConfiguration;
+ private String mTcpBufferSizes;
+ private ProxyInfo mHttpProxy;
/**
* Member variables accessed both from within the StateMachine thread
@@ -293,6 +339,26 @@
sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
}
+ /**
+ * Set the TCP buffer sizes to use.
+ *
+ * This may be called, repeatedly, at any time before or after a call to
+ * #startProvisioning(). The setting is cleared upon calling #stop().
+ */
+ public void setTcpBufferSizes(String tcpBufferSizes) {
+ sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
+ }
+
+ /**
+ * Set the HTTP Proxy configuration to use.
+ *
+ * This may be called, repeatedly, at any time before or after a call to
+ * #startProvisioning(). The setting is cleared upon calling #stop().
+ */
+ public void setHttpProxy(ProxyInfo proxyInfo) {
+ sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
+ }
+
public LinkProperties getLinkProperties() {
synchronized (mLock) {
return new LinkProperties(mLinkProperties);
@@ -306,26 +372,7 @@
@Override
protected String getWhatToString(int what) {
- // TODO: Investigate switching to reflection.
- switch (what) {
- case CMD_STOP:
- return "CMD_STOP";
- case CMD_START:
- return "CMD_START";
- case CMD_CONFIRM:
- return "CMD_CONFIRM";
- case EVENT_PRE_DHCP_ACTION_COMPLETE:
- return "EVENT_PRE_DHCP_ACTION_COMPLETE";
- case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
- return "EVENT_NETLINK_LINKPROPERTIES_CHANGED";
- case DhcpClient.CMD_PRE_DHCP_ACTION:
- return "DhcpClient.CMD_PRE_DHCP_ACTION";
- case DhcpClient.CMD_POST_DHCP_ACTION:
- return "DhcpClient.CMD_POST_DHCP_ACTION";
- case DhcpClient.CMD_ON_QUIT:
- return "DhcpClient.CMD_ON_QUIT";
- }
- return "UNKNOWN:" + Integer.toString(what);
+ return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
}
@Override
@@ -355,8 +402,10 @@
// assigned to the interface, etc.
private void resetLinkProperties() {
mNetlinkTracker.clearLinkProperties();
- mDhcpResults = null;
mConfiguration = null;
+ mDhcpResults = null;
+ mTcpBufferSizes = "";
+ mHttpProxy = null;
synchronized (mLock) {
mLinkProperties = new LinkProperties();
@@ -513,13 +562,33 @@
newLp.setDomains(mDhcpResults.domains);
}
+ // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
+ if (!TextUtils.isEmpty(mTcpBufferSizes)) {
+ newLp.setTcpBufferSizes(mTcpBufferSizes);
+ }
+ if (mHttpProxy != null) {
+ newLp.setHttpProxy(mHttpProxy);
+ }
+
if (VDBG) {
Log.d(mTag, "newLp{" + newLp + "}");
}
-
return newLp;
}
+ // Returns false if we have lost provisioning, true otherwise.
+ private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
+ final LinkProperties newLp = assembleLinkProperties();
+ if (linkPropertiesUnchanged(newLp)) {
+ return true;
+ }
+ final ProvisioningChange delta = setLinkProperties(newLp);
+ if (sendCallbacks) {
+ dispatchCallback(delta, newLp);
+ }
+ return (delta != ProvisioningChange.LOST_PROVISIONING);
+ }
+
private void clearIPv4Address() {
try {
final InterfaceConfiguration ifcg = new InterfaceConfiguration();
@@ -598,7 +667,17 @@
break;
case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
- setLinkProperties(assembleLinkProperties());
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
+ break;
+
+ case CMD_UPDATE_TCP_BUFFER_SIZES:
+ mTcpBufferSizes = (String) msg.obj;
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
+ break;
+
+ case CMD_UPDATE_HTTP_PROXY:
+ mHttpProxy = (ProxyInfo) msg.obj;
+ handleLinkPropertiesUpdate(NO_CALLBACKS);
break;
case DhcpClient.CMD_ON_QUIT:
@@ -729,18 +808,23 @@
}
break;
- case EVENT_NETLINK_LINKPROPERTIES_CHANGED: {
- final LinkProperties newLp = assembleLinkProperties();
- if (linkPropertiesUnchanged(newLp)) {
- break;
- }
- final ProvisioningChange delta = setLinkProperties(newLp);
- dispatchCallback(delta, newLp);
- if (delta == ProvisioningChange.LOST_PROVISIONING) {
+ case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+ if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
transitionTo(mStoppedState);
}
break;
- }
+
+ case CMD_UPDATE_TCP_BUFFER_SIZES:
+ mTcpBufferSizes = (String) msg.obj;
+ // This cannot possibly change provisioning state.
+ handleLinkPropertiesUpdate(SEND_CALLBACKS);
+ break;
+
+ case CMD_UPDATE_HTTP_PROXY:
+ mHttpProxy = (ProxyInfo) msg.obj;
+ // This cannot possibly change provisioning state.
+ handleLinkPropertiesUpdate(SEND_CALLBACKS);
+ break;
case DhcpClient.CMD_PRE_DHCP_ACTION:
if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml
new file mode 100644
index 0000000..c0977f7
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<profile-owner package="com.android.frameworks.servicestests" name="0" userId="0" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" />
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml
new file mode 100644
index 0000000..6b53840
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true">
+ <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2">
+ </admin>
+</policies>
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index f32f209..3a6b983 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -92,6 +92,7 @@
when(mMockContext.userManagerInternal.getBaseUserRestrictions(
eq(10))).thenReturn(DpmTestUtils.newRestrictions(
UserManager.DISALLOW_REMOVE_USER,
+ UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_SMS,
UserManager.DISALLOW_OUTGOING_CALLS,
UserManager.DISALLOW_WALLPAPER,
@@ -100,6 +101,7 @@
when(mMockContext.userManagerInternal.getBaseUserRestrictions(
eq(11))).thenReturn(DpmTestUtils.newRestrictions(
UserManager.DISALLOW_REMOVE_USER,
+ UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_SMS,
UserManager.DISALLOW_OUTGOING_CALLS,
UserManager.DISALLOW_WALLPAPER,
@@ -137,53 +139,142 @@
mContext.binder.restoreCallingIdentity(ident);
}
+ assertTrue(dpms.mOwners.hasDeviceOwner());
+ assertFalse(dpms.mOwners.hasProfileOwner(UserHandle.USER_SYSTEM));
+ assertTrue(dpms.mOwners.hasProfileOwner(10));
+ assertTrue(dpms.mOwners.hasProfileOwner(11));
+ assertFalse(dpms.mOwners.hasProfileOwner(12));
+
// Now all information should be migrated.
assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
+ assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(
+ UserHandle.USER_SYSTEM));
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12));
// Check the new base restrictions.
DpmTestUtils.assertRestrictions(
- DpmTestUtils.newRestrictions(),
+ DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_RECORD_AUDIO
+ ),
newBaseRestrictions.get(UserHandle.USER_SYSTEM));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_SMS,
- UserManager.DISALLOW_OUTGOING_CALLS
+ UserManager.DISALLOW_OUTGOING_CALLS,
+ UserManager.DISALLOW_RECORD_AUDIO,
+ UserManager.DISALLOW_WALLPAPER
),
newBaseRestrictions.get(10));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_SMS,
UserManager.DISALLOW_OUTGOING_CALLS,
- UserManager.DISALLOW_WALLPAPER
+ UserManager.DISALLOW_WALLPAPER,
+ UserManager.DISALLOW_RECORD_AUDIO
),
newBaseRestrictions.get(11));
// Check the new owner restrictions.
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
- UserManager.DISALLOW_ADD_USER,
- UserManager.DISALLOW_RECORD_AUDIO
+ UserManager.DISALLOW_ADD_USER
),
dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions());
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
- UserManager.DISALLOW_REMOVE_USER,
- UserManager.DISALLOW_WALLPAPER,
- UserManager.DISALLOW_RECORD_AUDIO
+ UserManager.DISALLOW_REMOVE_USER
),
dpms.getProfileOwnerAdminLocked(10).ensureUserRestrictions());
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
- UserManager.DISALLOW_REMOVE_USER,
- UserManager.DISALLOW_RECORD_AUDIO
+ UserManager.DISALLOW_REMOVE_USER
),
dpms.getProfileOwnerAdminLocked(11).ensureUserRestrictions());
}
+
+ public void testMigration2_profileOwnerOnUser0() throws Exception {
+ setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+ // Create the legacy owners & policies file.
+ DpmTestUtils.writeToFile(
+ (new File(mContext.dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(),
+ DpmTestUtils.readAsset(mRealTestContext,
+ "DevicePolicyManagerServiceMigrationTest2/legacy_device_owner.xml"));
+
+ DpmTestUtils.writeToFile(
+ (new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(),
+ DpmTestUtils.readAsset(mRealTestContext,
+ "DevicePolicyManagerServiceMigrationTest2/legacy_device_policies.xml"));
+
+ // Set up UserManager
+ when(mMockContext.userManagerInternal.getBaseUserRestrictions(
+ eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_ADD_USER,
+ UserManager.DISALLOW_RECORD_AUDIO,
+ UserManager.DISALLOW_SMS,
+ UserManager.DISALLOW_OUTGOING_CALLS));
+
+ final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>();
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Integer userId = (Integer) invocation.getArguments()[0];
+ Bundle bundle = (Bundle) invocation.getArguments()[1];
+
+ newBaseRestrictions.put(userId, bundle);
+
+ return null;
+ }
+ }).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration(
+ anyInt(), any(Bundle.class));
+
+ // Initialize DPM/DPMS and let it migrate the persisted information.
+ // (Need clearCallingIdentity() to pass permission checks.)
+
+ final DevicePolicyManagerServiceTestable dpms;
+
+ final long ident = mContext.binder.clearCallingIdentity();
+ try {
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+ dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
+
+ dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
+ dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
+ } finally {
+ mContext.binder.restoreCallingIdentity(ident);
+ }
+ assertFalse(dpms.mOwners.hasDeviceOwner());
+ assertTrue(dpms.mOwners.hasProfileOwner(UserHandle.USER_SYSTEM));
+
+ // Now all information should be migrated.
+ assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
+ assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(
+ UserHandle.USER_SYSTEM));
+
+ // Check the new base restrictions.
+ DpmTestUtils.assertRestrictions(
+ DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_RECORD_AUDIO
+ ),
+ newBaseRestrictions.get(UserHandle.USER_SYSTEM));
+
+ // Check the new owner restrictions.
+ DpmTestUtils.assertRestrictions(
+ DpmTestUtils.newRestrictions(
+ UserManager.DISALLOW_ADD_USER,
+ UserManager.DISALLOW_SMS,
+ UserManager.DISALLOW_OUTGOING_CALLS
+ ),
+ dpms.getProfileOwnerAdminLocked(UserHandle.USER_SYSTEM).ensureUserRestrictions());
+ }
}
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 b23ad50..212b37c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -32,6 +32,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
@@ -60,6 +61,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.validateMockitoUsage;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -208,7 +210,7 @@
/**
* Test for:
* {@link DevicePolicyManager#setActiveAdmin}
- * with replace=false and replace=true
+ * with replace=false and replace=true
* {@link DevicePolicyManager#isAdminActive}
* {@link DevicePolicyManager#isAdminActiveAsUser}
* {@link DevicePolicyManager#getActiveAdmins}
@@ -336,7 +338,7 @@
/**
* Test for:
* {@link DevicePolicyManager#setActiveAdmin}
- * with replace=false
+ * with replace=false
*/
public void testSetActiveAdmin_twiceWithoutReplace() throws Exception {
// 1. Make sure the caller has proper permissions.
@@ -999,7 +1001,8 @@
/**
* This essentially tests
- * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is private.)
+ * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is
+ * private.)
*
* We didn't use to persist the DO component class name, but now we do, and the above method
* finds the right component from a package name upon migration.
@@ -1196,7 +1199,7 @@
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
- );
+ );
reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1668,7 +1671,12 @@
// that the test user is not affiliated anymore.
dpm.clearProfileOwner(admin2);
final ComponentName admin = new ComponentName("test", "test");
- markPackageAsInstalled(admin.getPackageName(), null, DpmMockContext.CALLER_USER_HANDLE);
+
+ setUpPackageManagerForFakeAdmin(admin, DpmMockContext.CALLER_UID,
+ /* enabledSetting =*/ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+ /* appTargetSdk = */ null, admin2);
+
+ dpm.setActiveAdmin(admin, /* refreshing =*/ true, DpmMockContext.CALLER_USER_HANDLE);
assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
assertFalse(dpm.isAffiliatedUser());
@@ -1828,4 +1836,76 @@
mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
}
+
+ public void testSetMaximumTimeToLock() {
+ mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+ dpm.setActiveAdmin(admin1, /* replace =*/ false);
+ dpm.setActiveAdmin(admin2, /* replace =*/ false);
+
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin1, 0);
+ verifyScreenTimeoutCall(null, false);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin1, 1);
+ verifyScreenTimeoutCall(1, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, 10);
+ verifyScreenTimeoutCall(null, false);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin1, 5);
+ verifyScreenTimeoutCall(5, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, 4);
+ verifyScreenTimeoutCall(4, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin1, 0);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE);
+ verifyScreenTimeoutCall(Integer.MAX_VALUE, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, Integer.MAX_VALUE + 1);
+ verifyScreenTimeoutCall(Integer.MAX_VALUE, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ dpm.setMaximumTimeToLock(admin2, 10);
+ verifyScreenTimeoutCall(10, true);
+ reset(mMockContext.powerManagerInternal);
+ reset(mMockContext.settings);
+
+ // There's no restriction; shold be set to MAX.
+ dpm.setMaximumTimeToLock(admin2, 0);
+ verifyScreenTimeoutCall(Integer.MAX_VALUE, false);
+ }
+
+ private void verifyScreenTimeoutCall(Integer expectedTimeout,
+ boolean shouldStayOnWhilePluggedInBeCleared) {
+ if (expectedTimeout == null) {
+ verify(mMockContext.powerManagerInternal, times(0))
+ .setMaximumScreenOffTimeoutFromDeviceAdmin(anyInt());
+ } else {
+ verify(mMockContext.powerManagerInternal, times(1))
+ .setMaximumScreenOffTimeoutFromDeviceAdmin(eq(expectedTimeout));
+ }
+ // TODO Verify calls to settingsGlobalPutInt. Tried but somehow mockito threw
+ // UnfinishedVerificationException.
+ }
}
+
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 7a00098..ef8e420 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -44,11 +44,14 @@
import android.view.IWindowManager;
import org.junit.Assert;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -294,6 +297,50 @@
mUserInfos.add(uh);
when(userManager.getUsers()).thenReturn(mUserInfos);
+ when(userManager.getUserInfo(anyInt())).thenAnswer(
+ new Answer<UserInfo>() {
+ @Override
+ public UserInfo answer(InvocationOnMock invocation) throws Throwable {
+ final int userId = (int) invocation.getArguments()[0];
+ for (UserInfo ui : mUserInfos) {
+ if (ui.id == userId) {
+ return ui;
+ }
+ }
+ return null;
+ }
+ }
+ );
+ when(userManager.getProfiles(anyInt())).thenAnswer(
+ new Answer<List<UserInfo>>() {
+ @Override
+ public List<UserInfo> answer(InvocationOnMock invocation) throws Throwable {
+ final int userId = (int) invocation.getArguments()[0];
+ final ArrayList<UserInfo> ret = new ArrayList<UserInfo>();
+ UserInfo parent = null;
+ for (UserInfo ui : mUserInfos) {
+ if (ui.id == userId) {
+ parent = ui;
+ break;
+ }
+ }
+ if (parent == null) {
+ return ret;
+ }
+ ret.add(parent);
+ for (UserInfo ui : mUserInfos) {
+ if (ui.id == userId) {
+ continue;
+ }
+ if (ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+ && ui.profileGroupId == parent.profileGroupId) {
+ ret.add(ui);
+ }
+ }
+ return ret;
+ }
+ }
+ );
// Create a data directory.
final File dir = new File(dataDir, "user" + userId);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 53ca45d..ca43644 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -19,6 +19,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -96,12 +97,26 @@
protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
Integer enabledSetting, Integer appTargetSdk) throws Exception {
+ setUpPackageManagerForFakeAdmin(admin, packageUid, enabledSetting, appTargetSdk,
+ admin);
+ }
+
+ /**
+ * Set up a component in the mock package manager to be an active admin.
+ *
+ * @param admin ComponentName that's visible to the test code, which doesn't have to exist.
+ * @param copyFromAdmin package information for {@code admin} will be built based on this
+ * component's information.
+ */
+ protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
+ Integer enabledSetting, Integer appTargetSdk, ComponentName copyFromAdmin)
+ throws Exception {
// Set up getApplicationInfo().
final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
mRealTestContext.getPackageManager().getApplicationInfo(
- admin.getPackageName(),
+ copyFromAdmin.getPackageName(),
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
ai.enabledSetting = enabledSetting == null
@@ -111,6 +126,8 @@
ai.targetSdkVersion = appTargetSdk;
}
ai.uid = packageUid;
+ ai.packageName = admin.getPackageName();
+ ai.name = admin.getClassName();
doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
eq(admin.getPackageName()),
@@ -120,7 +137,7 @@
// Set up queryBroadcastReceivers().
final Intent resolveIntent = new Intent();
- resolveIntent.setComponent(admin);
+ resolveIntent.setComponent(copyFromAdmin);
final List<ResolveInfo> realResolveInfo =
mRealTestContext.getPackageManager().queryBroadcastReceivers(
resolveIntent,
@@ -132,7 +149,10 @@
realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
// We need to rewrite the UID in the activity info.
- realResolveInfo.get(0).activityInfo.applicationInfo = ai;
+ final ActivityInfo aci = realResolveInfo.get(0).activityInfo;
+ aci.applicationInfo = ai;
+ aci.packageName = admin.getPackageName();
+ aci.name = admin.getClassName();
doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser(
MockUtils.checkIntentComponent(admin),
diff --git a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
index 577c3a1..c786036 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobStoreTest.java
@@ -58,7 +58,7 @@
.setMinimumLatency(runFromMillis)
.setPersisted(true)
.build();
- final JobStatus ts = new JobStatus(task, SOME_UID, null, -1);
+ final JobStatus ts = JobStatus.createFromJobInfo(task, SOME_UID, null, -1);
mTaskStoreUnderTest.add(ts);
Thread.sleep(IO_WAIT);
// Manually load tasks from xml file.
@@ -91,8 +91,8 @@
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setPersisted(true)
.build();
- final JobStatus taskStatus1 = new JobStatus(task1, SOME_UID, null, -1);
- final JobStatus taskStatus2 = new JobStatus(task2, SOME_UID, null, -1);
+ final JobStatus taskStatus1 = JobStatus.createFromJobInfo(task1, SOME_UID, null, -1);
+ final JobStatus taskStatus2 = JobStatus.createFromJobInfo(task2, SOME_UID, null, -1);
mTaskStoreUnderTest.add(taskStatus1);
mTaskStoreUnderTest.add(taskStatus2);
Thread.sleep(IO_WAIT);
@@ -140,7 +140,7 @@
extras.putInt("into", 3);
b.setExtras(extras);
final JobInfo task = b.build();
- JobStatus taskStatus = new JobStatus(task, SOME_UID, null, -1);
+ JobStatus taskStatus = JobStatus.createFromJobInfo(task, SOME_UID, null, -1);
mTaskStoreUnderTest.add(taskStatus);
Thread.sleep(IO_WAIT);
@@ -157,7 +157,8 @@
.setPeriodic(10000L)
.setRequiresCharging(true)
.setPersisted(true);
- JobStatus taskStatus = new JobStatus(b.build(), SOME_UID, "com.google.android.gms", 0);
+ JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID,
+ "com.google.android.gms", 0);
mTaskStoreUnderTest.add(taskStatus);
Thread.sleep(IO_WAIT);
@@ -178,7 +179,7 @@
.setPeriodic(5*60*60*1000, 1*60*60*1000)
.setRequiresCharging(true)
.setPersisted(true);
- JobStatus taskStatus = new JobStatus(b.build(), SOME_UID, null, -1);
+ JobStatus taskStatus = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
mTaskStoreUnderTest.add(taskStatus);
Thread.sleep(IO_WAIT);
@@ -203,7 +204,8 @@
SystemClock.elapsedRealtime() + (TWO_HOURS * ONE_HOUR) + TWO_HOURS; // > period+flex
final long invalidEarlyRuntimeElapsedMillis =
invalidLateRuntimeElapsedMillis - TWO_HOURS; // Early is (late - period).
- final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage", 0 /* sourceUserId */,
+ final JobStatus js = new JobStatus(b.build(), SOME_UID, "somePackage",
+ 0 /* sourceUserId */,
invalidEarlyRuntimeElapsedMillis, invalidLateRuntimeElapsedMillis);
mTaskStoreUnderTest.add(js);
@@ -229,7 +231,7 @@
.setOverrideDeadline(5000)
.setPriority(42)
.setPersisted(true);
- final JobStatus js = new JobStatus(b.build(), SOME_UID, null, -1);
+ final JobStatus js = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
mTaskStoreUnderTest.add(js);
Thread.sleep(IO_WAIT);
final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
@@ -245,12 +247,12 @@
JobInfo.Builder b = new Builder(42, mComponent)
.setOverrideDeadline(10000)
.setPersisted(false);
- JobStatus jsNonPersisted = new JobStatus(b.build(), SOME_UID, null, -1);
+ JobStatus jsNonPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
mTaskStoreUnderTest.add(jsNonPersisted);
b = new Builder(43, mComponent)
.setOverrideDeadline(10000)
.setPersisted(true);
- JobStatus jsPersisted = new JobStatus(b.build(), SOME_UID, null, -1);
+ JobStatus jsPersisted = JobStatus.createFromJobInfo(b.build(), SOME_UID, null, -1);
mTaskStoreUnderTest.add(jsPersisted);
Thread.sleep(IO_WAIT);
final ArraySet<JobStatus> jobStatusSet = new ArraySet<JobStatus>();
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
new file mode 100644
index 0000000..b9e9aa9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
@@ -0,0 +1,634 @@
+/*
+ * 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.net;
+
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.when;
+
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.ROAMING_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import android.app.usage.NetworkStatsManager;
+import android.net.DataUsageRequest;
+import android.net.NetworkIdentity;
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Process;
+
+import android.os.ConditionVariable;
+import android.os.Looper;
+import android.os.Messenger;
+import android.os.Message;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+
+import com.android.internal.net.VpnInfo;
+import com.android.server.net.NetworkStatsService;
+import com.android.server.net.NetworkStatsServiceTest.IdleableHandlerThread;
+import com.android.server.net.NetworkStatsServiceTest.LatchedHandler;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link NetworkStatsObservers}.
+ */
+public class NetworkStatsObserversTest extends TestCase {
+ private static final String TEST_IFACE = "test0";
+ private static final String TEST_IFACE2 = "test1";
+ private static final long TEST_START = 1194220800000L;
+
+ private static final String IMSI_1 = "310004";
+ private static final String IMSI_2 = "310260";
+ private static final String TEST_SSID = "AndroidAP";
+
+ private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
+ private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
+ private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
+
+ private static final int UID_RED = UserHandle.PER_USER_RANGE + 1;
+ private static final int UID_BLUE = UserHandle.PER_USER_RANGE + 2;
+ private static final int UID_GREEN = UserHandle.PER_USER_RANGE + 3;
+ private static final int UID_ANOTHER_USER = 2 * UserHandle.PER_USER_RANGE + 4;
+
+ private static final long WAIT_TIMEOUT = 500; // 1/2 sec
+ private static final long THRESHOLD_BYTES = 2 * MB_IN_BYTES;
+ private static final long BASE_BYTES = 7 * MB_IN_BYTES;
+ private static final int INVALID_TYPE = -1;
+
+ private static final int[] NO_UIDS = null;
+ private static final VpnInfo[] VPN_INFO = new VpnInfo[0];
+
+ private long mElapsedRealtime;
+
+ private IdleableHandlerThread mObserverHandlerThread;
+ private Handler mObserverNoopHandler;
+
+ private LatchedHandler mHandler;
+ private ConditionVariable mCv;
+
+ private NetworkStatsObservers mStatsObservers;
+ private Messenger mMessenger;
+ private ArrayMap<String, NetworkIdentitySet> mActiveIfaces;
+ private ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces;
+
+ @Mock private IBinder mockBinder;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+
+ mObserverHandlerThread = new IdleableHandlerThread("HandlerThread");
+ mObserverHandlerThread.start();
+ final Looper observerLooper = mObserverHandlerThread.getLooper();
+ mStatsObservers = new NetworkStatsObservers() {
+ @Override
+ protected Looper getHandlerLooperLocked() {
+ return observerLooper;
+ }
+ };
+
+ mCv = new ConditionVariable();
+ mHandler = new LatchedHandler(Looper.getMainLooper(), mCv);
+ mMessenger = new Messenger(mHandler);
+
+ mActiveIfaces = new ArrayMap<>();
+ mActiveUidIfaces = new ArrayMap<>();
+ }
+
+ public void testRegister_thresholdTooLow_setsDefaultThreshold() throws Exception {
+ long thresholdTooLowBytes = 1L;
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, thresholdTooLowBytes);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ }
+
+ public void testRegister_highThreshold_accepted() throws Exception {
+ long highThresholdBytes = 2 * THRESHOLD_BYTES;
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, highThresholdBytes);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(highThresholdBytes, request.thresholdInBytes);
+ }
+
+ public void testRegister_twoRequests_twoIds() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request1 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request1.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request1.templates));
+ assertNull(request1.uids);
+ assertEquals(THRESHOLD_BYTES, request1.thresholdInBytes);
+
+ DataUsageRequest request2 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request2.requestId > request1.requestId);
+ assertTrue(Arrays.deepEquals(templates, request2.templates));
+ assertNull(request2.uids);
+ assertEquals(THRESHOLD_BYTES, request2.thresholdInBytes);
+ }
+
+ public void testRegister_defaultAccess_otherUids_securityException() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ int[] uids = new int[] { UID_RED, UID_BLUE, UID_GREEN };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
+
+ try {
+ mStatsObservers.register(inputRequest, mMessenger, mockBinder, UID_RED,
+ NetworkStatsAccess.Level.DEFAULT);
+ fail("Should have denied access");
+ } catch (SecurityException expected) {}
+ }
+
+ public void testRegister_userAccess_otherUidsSameUser()
+ throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ int[] uids = new int[] { UID_RED, UID_BLUE, UID_GREEN };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.USER);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertTrue(Arrays.equals(uids, request.uids));
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ }
+
+ public void testRegister_defaultAccess_sameUid() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ int[] uids = new int[] { UID_RED };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.DEFAULT);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertTrue(Arrays.equals(uids, request.uids));
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ }
+
+ public void testUnregister_unknownRequest_noop() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest unknownRequest = new DataUsageRequest(
+ 123456 /* id */, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ mStatsObservers.unregister(unknownRequest, UID_RED);
+ }
+
+ public void testUnregister_knownRequest_releasesCaller() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ mStatsObservers.unregister(request, Process.SYSTEM_UID);
+ waitForObserverToIdle();
+
+ Mockito.verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+ }
+
+ public void testUnregister_knownRequest_invalidUid_doesNotUnregister() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+ Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
+
+ mStatsObservers.unregister(request, UID_BLUE);
+ waitForObserverToIdle();
+
+ Mockito.verifyZeroInteractions(mockBinder);
+ }
+
+ public void testUpdateStats_initialSample_doesNotNotify() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
+ NetworkStats uidSnapshot = null;
+
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_belowThreshold_doesNotNotify() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
+ NetworkStats uidSnapshot = null;
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES + 1024L, 10L, BASE_BYTES + 2048L, 20L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ mCv.block(WAIT_TIMEOUT);
+ assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_aboveThresholdNetwork_notifies() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
+ NetworkStats uidSnapshot = null;
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES + THRESHOLD_BYTES, 12L,
+ BASE_BYTES + THRESHOLD_BYTES, 22L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_aboveThresholdMultipleNetwork_notifies() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1, sTemplateImsi2 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.DEVICESUMMARY);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet1 = new NetworkIdentitySet();
+ identSet1.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE, identSet1);
+
+ NetworkIdentitySet identSet2 = new NetworkIdentitySet();
+ identSet2.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_2, null /* networkId */, false /* roaming */));
+ mActiveIfaces.put(TEST_IFACE2, identSet2);
+
+ // Baseline
+ NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L)
+ .addIfaceValues(TEST_IFACE2, BASE_BYTES + 1234L, 18L, BASE_BYTES, 12L);
+ NetworkStats uidSnapshot = null;
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta - traffic on IMSI2
+ xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
+ .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L)
+ .addIfaceValues(TEST_IFACE2, BASE_BYTES + THRESHOLD_BYTES, 22L,
+ BASE_BYTES + THRESHOLD_BYTES, 24L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_aboveThresholdUid_notifies() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ int[] uids = new int[] { UID_RED, UID_BLUE, UID_GREEN };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertTrue(Arrays.equals(uids,request.uids));
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_defaultAccess_noUid_notifiesSameUid() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.DEFAULT);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_defaultAccess_noUid_usageOtherUid_doesNotNotify() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_BLUE, NetworkStatsAccess.Level.DEFAULT);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_userAccess_usageSameUser_notifies() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_BLUE, NetworkStatsAccess.Level.USER);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.mLastMessageType);
+ }
+
+ public void testUpdateStats_userAccess_usageAnotherUser_doesNotNotify() throws Exception {
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1 };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, NO_UIDS, THRESHOLD_BYTES);
+
+ DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
+ UID_RED, NetworkStatsAccess.Level.USER);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
+
+ NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(
+ TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ IMSI_1, null /* networkId */, false /* roaming */));
+ mActiveUidIfaces.put(TEST_IFACE, identSet);
+
+ // Baseline
+ NetworkStats xtSnapshot = null;
+ NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+
+ // Delta
+ uidSnapshot = new NetworkStats(TEST_START+ 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
+ .addValues(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
+ mStatsObservers.updateStats(
+ xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces,
+ VPN_INFO, TEST_START);
+ waitForObserverToIdle();
+
+ assertTrue(mCv.block(WAIT_TIMEOUT));
+ assertEquals(INVALID_TYPE, mHandler.mLastMessageType);
+ }
+
+ private void waitForObserverToIdle() {
+ // Send dummy message to make sure that any previous message has been handled
+ mHandler.sendMessage(mHandler.obtainMessage(-1));
+ mObserverHandlerThread.waitForIdle(WAIT_TIMEOUT);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
similarity index 73%
rename from services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
rename to services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
index 8cbd32d..4f6c7b9 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.net;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
@@ -43,6 +43,7 @@
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.anyLong;
+import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.eq;
@@ -54,7 +55,10 @@
import android.app.IAlarmListener;
import android.app.IAlarmManager;
import android.app.PendingIntent;
+import android.app.usage.NetworkStatsManager;
+import android.content.Context;
import android.content.Intent;
+import android.net.DataUsageRequest;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsSession;
@@ -65,7 +69,17 @@
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.INetworkManagementService;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Messenger;
+import android.os.MessageQueue;
+import android.os.MessageQueue.IdleHandler;
+import android.os.Message;
+import android.os.PowerManager;
import android.os.WorkSource;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
@@ -74,6 +88,7 @@
import android.util.TrustedTime;
import com.android.internal.net.VpnInfo;
+import com.android.server.BroadcastInterceptingContext;
import com.android.server.net.NetworkStatsService;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -85,6 +100,7 @@
import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -113,16 +129,20 @@
private static final int UID_BLUE = 1002;
private static final int UID_GREEN = 1003;
+ private static final long WAIT_TIMEOUT = 2 * 1000; // 2 secs
+ private static final int INVALID_TYPE = -1;
+
private long mElapsedRealtime;
private BroadcastInterceptingContext mServiceContext;
private File mStatsDir;
private INetworkManagementService mNetManager;
- private IAlarmManager mAlarmManager;
private TrustedTime mTime;
private NetworkStatsSettings mSettings;
private IConnectivityManager mConnManager;
+ private IdleableHandlerThread mHandlerThread;
+ private Handler mHandler;
private NetworkStatsService mService;
private INetworkStatsSession mSession;
@@ -139,13 +159,28 @@
}
mNetManager = createMock(INetworkManagementService.class);
- mAlarmManager = createMock(IAlarmManager.class);
+
+ // TODO: Mock AlarmManager when migrating this test to Mockito.
+ AlarmManager alarmManager = (AlarmManager) mServiceContext
+ .getSystemService(Context.ALARM_SERVICE);
mTime = createMock(TrustedTime.class);
mSettings = createMock(NetworkStatsSettings.class);
mConnManager = createMock(IConnectivityManager.class);
+ PowerManager powerManager = (PowerManager) mServiceContext.getSystemService(
+ Context.POWER_SERVICE);
+ PowerManager.WakeLock wakeLock =
+ powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
mService = new NetworkStatsService(
- mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir, mSettings);
+ mServiceContext, mNetManager, alarmManager, wakeLock, mTime,
+ TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(),
+ mStatsDir, getBaseDir(mStatsDir));
+ mHandlerThread = new IdleableHandlerThread("HandlerThread");
+ mHandlerThread.start();
+ Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService);
+ mHandler = new Handler(mHandlerThread.getLooper(), callback);
+ mService.setHandler(mHandler, callback);
mService.bindConnectivityManager(mConnManager);
mElapsedRealtime = 0L;
@@ -178,7 +213,6 @@
mStatsDir = null;
mNetManager = null;
- mAlarmManager = null;
mTime = null;
mSettings = null;
mConnManager = null;
@@ -217,7 +251,7 @@
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
@@ -234,7 +268,7 @@
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0);
@@ -282,7 +316,7 @@
mService.incrementOperationCount(UID_RED, 0xFAAD, 6);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
@@ -362,7 +396,7 @@
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
@@ -380,7 +414,7 @@
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify identical stats, but spread across 4 buckets now
history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
@@ -420,7 +454,7 @@
mService.incrementOperationCount(UID_RED, 0xF00D, 10);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
@@ -446,7 +480,7 @@
replay();
mService.forceUpdateIfaces();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
verifyAndReset();
// create traffic on second network
@@ -465,7 +499,7 @@
mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify original history still intact
assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
@@ -511,7 +545,7 @@
mService.incrementOperationCount(UID_RED, 0xFAAD, 10);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0);
@@ -578,7 +612,7 @@
mService.incrementOperationCount(UID_RED, 0xF00D, 5);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
@@ -598,7 +632,7 @@
replay();
mService.forceUpdateIfaces();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
verifyAndReset();
// create traffic on second network
@@ -616,7 +650,7 @@
mService.incrementOperationCount(UID_RED, 0xFAAD, 5);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify that ALL_MOBILE template combines both
assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
@@ -652,7 +686,7 @@
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateWifi, UID_RED, 50L, 5L, 50L, 5L, 1);
@@ -671,7 +705,7 @@
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// first verify entire history present
NetworkStats stats = mSession.getSummaryForAllUid(
@@ -722,7 +756,7 @@
mService.incrementOperationCount(UID_RED, 0xF00D, 1);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
@@ -744,7 +778,7 @@
mService.incrementOperationCount(UID_RED, 0xFAAD, 1);
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// test that we combined correctly
assertUidTotal(sTemplateWifi, UID_RED, 160L, 4L, 160L, 4L, 2);
@@ -795,7 +829,7 @@
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
@@ -843,7 +877,7 @@
expectNetworkStatsPoll();
replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ forcePollAndWaitForIdle();
// verify service recorded history
assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
@@ -853,6 +887,285 @@
}
+ public void testRegisterDataUsageCallback_network() throws Exception {
+ // pretend that wifi network comes online; service should ask about full
+ // network state, and poll any existing interfaces before updating.
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkState(buildWifiState());
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
+
+ replay();
+ mService.forceUpdateIfaces();
+
+ // verify service has empty history for wifi
+ assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
+ verifyAndReset();
+
+ String callingPackage = "the.calling.package";
+ long thresholdInBytes = 1L; // very small; should be overriden by framework
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateWifi };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, null /* uids */, thresholdInBytes);
+
+ // Create a messenger that waits for callback activity
+ ConditionVariable cv = new ConditionVariable(false);
+ LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
+ Messenger messenger = new Messenger(latchedHandler);
+
+ // Allow binder to connect
+ IBinder mockBinder = createMock(IBinder.class);
+ mockBinder.linkToDeath((IBinder.DeathRecipient) anyObject(), anyInt());
+ EasyMock.replay(mockBinder);
+
+ // Force poll
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+ replay();
+
+ // Register and verify request and that binder was called
+ DataUsageRequest request =
+ mService.registerDataUsageCallback(callingPackage, inputRequest,
+ messenger, mockBinder);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertNull(request.uids);
+ long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
+ assertEquals(minThresholdInBytes, request.thresholdInBytes);
+
+ // Send dummy message to make sure that any previous message has been handled
+ mHandler.sendMessage(mHandler.obtainMessage(-1));
+ mHandlerThread.waitForIdle(WAIT_TIMEOUT);
+
+ verifyAndReset();
+
+ // Make sure that the caller binder gets connected
+ EasyMock.verify(mockBinder);
+ EasyMock.reset(mockBinder);
+
+ // modify some number on wifi, and trigger poll event
+ // not enough traffic to call data usage callback
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+
+ replay();
+ forcePollAndWaitForIdle();
+
+ // verify service recorded history
+ verifyAndReset();
+ assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
+
+ // make sure callback has not being called
+ assertEquals(INVALID_TYPE, latchedHandler.mLastMessageType);
+
+ // and bump forward again, with counters going higher. this is
+ // important, since it will trigger the data usage callback
+ incrementCurrentTime(DAY_IN_MILLIS);
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
+ .addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+
+ replay();
+ forcePollAndWaitForIdle();
+
+ // verify service recorded history
+ assertNetworkTotal(sTemplateWifi, 4096000L, 4L, 8192000L, 8L, 0);
+ verifyAndReset();
+
+ // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
+ assertTrue(cv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.mLastMessageType);
+ cv.close();
+
+ // Allow binder to disconnect
+ expect(mockBinder.unlinkToDeath((IBinder.DeathRecipient) anyObject(), anyInt()))
+ .andReturn(true);
+ EasyMock.replay(mockBinder);
+
+ // Unregister request
+ mService.unregisterDataUsageRequest(request);
+
+ // Wait for the caller to ack receipt of CALLBACK_RELEASED
+ assertTrue(cv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType);
+
+ // Make sure that the caller binder gets disconnected
+ EasyMock.verify(mockBinder);
+ }
+
+ public void testRegisterDataUsageCallback_uids() throws Exception {
+ // pretend that network comes online
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */));
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
+
+ replay();
+ mService.forceUpdateIfaces();
+ verifyAndReset();
+
+ String callingPackage = "the.calling.package";
+ long thresholdInBytes = 10 * 1024 * 1024; // 10 MB
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1, sTemplateImsi2 };
+ int[] uids = new int[] { UID_RED };
+ DataUsageRequest inputRequest = new DataUsageRequest(
+ DataUsageRequest.REQUEST_ID_UNSET, templates, uids, thresholdInBytes);
+
+ // Create a messenger that waits for callback activity
+ ConditionVariable cv = new ConditionVariable(false);
+ cv.close();
+ LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
+ Messenger messenger = new Messenger(latchedHandler);
+
+ // Allow binder to connect
+ IBinder mockBinder = createMock(IBinder.class);
+ mockBinder.linkToDeath((IBinder.DeathRecipient) anyObject(), anyInt());
+ EasyMock.replay(mockBinder);
+
+ // Force poll
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectNetworkStatsPoll();
+ replay();
+
+ // Register and verify request and that binder was called
+ DataUsageRequest request =
+ mService.registerDataUsageCallback(callingPackage, inputRequest,
+ messenger, mockBinder);
+ assertTrue(request.requestId > 0);
+ assertTrue(Arrays.deepEquals(templates, request.templates));
+ assertTrue(Arrays.equals(uids, request.uids));
+ assertEquals(thresholdInBytes, request.thresholdInBytes);
+
+ // Wait for service to handle internal MSG_REGISTER_DATA_USAGE_LISTENER
+ mHandler.sendMessage(mHandler.obtainMessage(-1));
+ mHandlerThread.waitForIdle(WAIT_TIMEOUT);
+
+ verifyAndReset();
+
+ // Make sure that the caller binder gets connected
+ EasyMock.verify(mockBinder);
+ EasyMock.reset(mockBinder);
+
+ // modify some number on mobile interface, and trigger poll event
+ // not enough traffic to call data usage callback
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT, 128L, 2L,
+ 128L, 2L, 0L)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT, 64L, 1L, 64L,
+ 1L, 0L));
+ expectNetworkStatsPoll();
+
+ replay();
+ forcePollAndWaitForIdle();
+
+ // verify service recorded history
+ assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
+
+ // verify entire history present
+ NetworkStats stats = mSession.getSummaryForAllUid(
+ sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertEquals(2, stats.size());
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING, 128L, 2L,
+ 128L, 2L, 0);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_ROAMING, 64L, 1L, 64L,
+ 1L, 0);
+
+ verifyAndReset();
+
+ // make sure callback has not being called
+ assertEquals(INVALID_TYPE, latchedHandler.mLastMessageType);
+
+ // and bump forward again, with counters going higher. this is
+ // important, since it will trigger the data usage callback
+ incrementCurrentTime(DAY_IN_MILLIS);
+ expectCurrentTime();
+ expectDefaultSettings();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_DEFAULT,
+ 128000000L, 2L, 128000000L, 2L, 0L)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_DEFAULT,
+ 64000000L, 1L, 64000000L, 1L, 0L));
+ expectNetworkStatsPoll();
+
+ replay();
+ forcePollAndWaitForIdle();
+
+ // verify service recorded history
+ assertUidTotal(sTemplateImsi1, UID_RED, 128000000L, 2L, 128000000L, 2L, 0);
+
+ // verify entire history present
+ stats = mSession.getSummaryForAllUid(
+ sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertEquals(2, stats.size());
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, ROAMING_ROAMING,
+ 128000000L, 2L, 128000000L, 2L, 0);
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, ROAMING_ROAMING,
+ 64000000L, 1L, 64000000L, 1L, 0);
+
+ verifyAndReset();
+
+ // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
+ assertTrue(cv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.mLastMessageType);
+ cv.close();
+
+ // Allow binder to disconnect
+ expect(mockBinder.unlinkToDeath((IBinder.DeathRecipient) anyObject(), anyInt()))
+ .andReturn(true);
+ EasyMock.replay(mockBinder);
+
+ // Unregister request
+ mService.unregisterDataUsageRequest(request);
+
+ // Wait for the caller to ack receipt of CALLBACK_RELEASED
+ assertTrue(cv.block(WAIT_TIMEOUT));
+ assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.mLastMessageType);
+
+ // Make sure that the caller binder gets disconnected
+ EasyMock.verify(mockBinder);
+ }
+
+ public void testUnregisterDataUsageCallback_unknown_noop() throws Exception {
+ String callingPackage = "the.calling.package";
+ long thresholdInBytes = 10 * 1024 * 1024; // 10 MB
+ NetworkTemplate[] templates = new NetworkTemplate[] { sTemplateImsi1, sTemplateImsi2 };
+ DataUsageRequest unknownRequest = new DataUsageRequest(
+ 2, templates, null /* uids */, thresholdInBytes);
+
+ mService.unregisterDataUsageRequest(unknownRequest);
+ }
+
+ private static File getBaseDir(File statsDir) {
+ File baseDir = new File(statsDir, "netstats");
+ baseDir.mkdirs();
+ return baseDir;
+ }
+
private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
long txBytes, long txPackets, int operations) throws Exception {
assertNetworkTotal(template, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
@@ -894,16 +1207,6 @@
}
private void expectSystemReady() throws Exception {
- mAlarmManager.remove(isA(PendingIntent.class), EasyMock.<IAlarmListener>isNull());
- expectLastCall().anyTimes();
-
- mAlarmManager.set(eq(getContext().getPackageName()),
- eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(),
- anyInt(), isA(PendingIntent.class), EasyMock.<IAlarmListener>isNull(),
- EasyMock.<String>isNull(), EasyMock.<WorkSource>isNull(),
- EasyMock.<AlarmManager.AlarmClockInfo>isNull());
- expectLastCall().anyTimes();
-
mNetManager.setGlobalAlert(anyLong());
expectLastCall().atLeastOnce();
@@ -1093,11 +1396,75 @@
}
private void replay() {
- EasyMock.replay(mNetManager, mAlarmManager, mTime, mSettings, mConnManager);
+ EasyMock.replay(mNetManager, mTime, mSettings, mConnManager);
}
private void verifyAndReset() {
- EasyMock.verify(mNetManager, mAlarmManager, mTime, mSettings, mConnManager);
- EasyMock.reset(mNetManager, mAlarmManager, mTime, mSettings, mConnManager);
+ EasyMock.verify(mNetManager, mTime, mSettings, mConnManager);
+ EasyMock.reset(mNetManager, mTime, mSettings, mConnManager);
}
+
+ private void forcePollAndWaitForIdle() {
+ mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
+ // Send dummy message to make sure that any previous message has been handled
+ mHandler.sendMessage(mHandler.obtainMessage(-1));
+ mHandlerThread.waitForIdle(WAIT_TIMEOUT);
+ }
+
+ static class LatchedHandler extends Handler {
+ private final ConditionVariable mCv;
+ int mLastMessageType = INVALID_TYPE;
+
+ LatchedHandler(Looper looper, ConditionVariable cv) {
+ super(looper);
+ mCv = cv;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ mLastMessageType = msg.what;
+ mCv.open();
+ super.handleMessage(msg);
+ }
+ }
+
+ /**
+ * A subclass of HandlerThread that allows callers to wait for it to become idle. waitForIdle
+ * will return immediately if the handler is already idle.
+ */
+ static class IdleableHandlerThread extends HandlerThread {
+ private IdleHandler mIdleHandler;
+
+ public IdleableHandlerThread(String name) {
+ super(name);
+ }
+
+ public void waitForIdle(long timeoutMs) {
+ final ConditionVariable cv = new ConditionVariable();
+ final MessageQueue queue = getLooper().getQueue();
+
+ synchronized (queue) {
+ if (queue.isIdle()) {
+ return;
+ }
+
+ assertNull("BUG: only one idle handler allowed", mIdleHandler);
+ mIdleHandler = new IdleHandler() {
+ public boolean queueIdle() {
+ cv.open();
+ mIdleHandler = null;
+ return false; // Remove the handler.
+ }
+ };
+ queue.addIdleHandler(mIdleHandler);
+ }
+
+ if (!cv.block(timeoutMs)) {
+ fail("HandlerThread " + getName() + " did not become idle after " + timeoutMs
+ + " ms");
+ queue.removeIdleHandler(mIdleHandler);
+ }
+ }
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index 31182fc..f1fe346 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -25,7 +25,6 @@
import org.mockito.MockitoAnnotations;
import android.app.Notification;
-import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.AndroidTestCase;
@@ -55,14 +54,13 @@
UserHandle user = UserHandle.ALL;
mHelper = new RankingHelper(getContext(), handler, mUsageStats,
- new String[] {TopicImportanceExtractor.class.getName()});
+ new String[] {ImportanceExtractor.class.getName()});
mNotiGroupGSortA = new Notification.Builder(getContext())
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
.setWhen(1205)
- .setTopic(new Notification.Topic("A", "a"))
.build();
mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiGroupGSortA, user));
@@ -72,7 +70,6 @@
.setGroup("G")
.setSortKey("B")
.setWhen(1200)
- .setTopic(new Notification.Topic("A", "a"))
.build();
mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiGroupGSortB, user));
@@ -80,7 +77,6 @@
mNotiNoGroup = new Notification.Builder(getContext())
.setContentTitle("C")
.setWhen(1201)
- .setTopic(new Notification.Topic("C", "c"))
.build();
mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiNoGroup, user));
@@ -88,7 +84,6 @@
mNotiNoGroup2 = new Notification.Builder(getContext())
.setContentTitle("D")
.setWhen(1202)
- .setTopic(new Notification.Topic("D", "d"))
.build();
mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiNoGroup2, user));
@@ -97,7 +92,6 @@
.setContentTitle("E")
.setWhen(1201)
.setSortKey("A")
- .setTopic(new Notification.Topic("E", "e"))
.build();
mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
"package", "package", 1, null, 0, 0, 0, mNotiNoGroupSortA, user));
@@ -152,26 +146,4 @@
ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>();
mHelper.sort(notificationList);
}
-
- @SmallTest
- public void testTopicImportanceExtractor() throws Exception {
- mHelper.setImportance("package", 0, new Notification.Topic("A", "a"), IMPORTANCE_MAX);
- // There is no B. There never was a b. Moving on...
- mHelper.setImportance("package", 0, new Notification.Topic("C", "c"), IMPORTANCE_HIGH);
- mHelper.setImportance("package", 0, new Notification.Topic("D", "d"), IMPORTANCE_LOW);
- // watch out: different package.
- mHelper.setImportance("package2", 0, new Notification.Topic("E", "e"), IMPORTANCE_NONE);
-
- TopicImportanceExtractor validator = mHelper.findExtractor(TopicImportanceExtractor.class);
- validator.process(mRecordGroupGSortA);
- validator.process(mRecordGroupGSortB);
- validator.process(mRecordNoGroup);
- validator.process(mRecordNoGroup2);
- validator.process(mRecordNoGroupSortA);
- assertTrue(mRecordGroupGSortA.getTopicImportance() == IMPORTANCE_MAX);
- assertTrue(mRecordGroupGSortB.getTopicImportance() == IMPORTANCE_MAX);
- assertTrue(mRecordNoGroup.getTopicImportance() == IMPORTANCE_HIGH);
- assertTrue(mRecordNoGroup2.getTopicImportance() == IMPORTANCE_LOW);
- assertTrue(mRecordNoGroupSortA.getTopicImportance() == IMPORTANCE_UNSPECIFIED);
- }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index acc752a..8e891bf 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -431,17 +431,17 @@
List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
PackageManager.MATCH_DISABLED_COMPONENTS,
userId);
- synchronized (mLock) {
- final int packageCount = packages.size();
- for (int p = 0; p < packageCount; p++) {
- final PackageInfo pi = packages.get(p);
- final String packageName = pi.packageName;
- final boolean isIdle = isAppIdleFiltered(packageName,
- UserHandle.getAppId(pi.applicationInfo.uid),
- userId, elapsedRealtime);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
- userId, isIdle ? 1 : 0, packageName));
- if (isIdle) {
+ final int packageCount = packages.size();
+ for (int p = 0; p < packageCount; p++) {
+ final PackageInfo pi = packages.get(p);
+ final String packageName = pi.packageName;
+ final boolean isIdle = isAppIdleFiltered(packageName,
+ UserHandle.getAppId(pi.applicationInfo.uid),
+ userId, elapsedRealtime);
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
+ userId, isIdle ? 1 : 0, packageName));
+ if (isIdle) {
+ synchronized (mLock) {
mAppIdleHistory.setIdle(packageName, userId, elapsedRealtime);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index cde47bd..b4c4bf8 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -198,6 +198,7 @@
return STATUS_ERROR;
}
modelData.setHandle(handle[0]);
+ modelData.setLoaded();
}
modelData.setCallback(callback);
modelData.setRecognitionConfig(recognitionConfig);
@@ -346,7 +347,7 @@
return STATUS_ERROR;
}
- if (currentCallback == null || !modelData.modelStarted()) {
+ if (currentCallback == null || !modelData.isModelStarted()) {
// startRecognition hasn't been called or it failed.
Slog.w(TAG, "Attempting stopRecognition without a successful startRecognition");
return STATUS_ERROR;
@@ -451,7 +452,7 @@
// Stop all generic recognition models.
for (ModelData model : mGenericModelDataMap.values()) {
- if (model.modelStarted()) {
+ if (model.isModelStarted()) {
int status = stopGenericRecognitionLocked(model,
false /* do not notify for synchronous calls */);
if (status != STATUS_OK) {
@@ -970,7 +971,7 @@
}
for (UUID modelId : mGenericModelDataMap.keySet()) {
ModelData modelData = mGenericModelDataMap.get(modelId);
- if (modelData.modelStarted()) {
+ if (modelData.isModelStarted()) {
mRecognitionRunning = true;
return mRecognitionRunning;
}
@@ -1001,7 +1002,6 @@
// to SoundModel.TYPE_UNKNOWN;
private int mModelType = SoundModel.TYPE_UNKNOWN;
private IRecognitionStatusCallback mCallback = null;
- private SoundModel mSoundModel = null;
private RecognitionConfig mRecognitionConfig = null;
@@ -1026,8 +1026,7 @@
}
synchronized boolean isModelLoaded() {
- return (mModelState == MODEL_LOADED || mModelState == MODEL_STARTED) &&
- mSoundModel != null;
+ return (mModelState == MODEL_LOADED || mModelState == MODEL_STARTED);
}
synchronized void setStarted() {
@@ -1038,13 +1037,16 @@
mModelState = MODEL_LOADED;
}
- synchronized boolean modelStarted() {
+ synchronized void setLoaded() {
+ mModelState = MODEL_LOADED;
+ }
+
+ synchronized boolean isModelStarted() {
return mModelState == MODEL_STARTED;
}
synchronized void clearState() {
mModelState = MODEL_NOTLOADED;
- mSoundModel = null;
mModelHandle = INVALID_VALUE;
}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index bec1e4f..84cffe1 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -191,6 +191,11 @@
}
@Override
+ public File getDataDir() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public File getFilesDir() {
throw new UnsupportedOperationException();
}
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.mk
index 616a11b..39ad0ac 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.mk
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/Android.mk
@@ -38,6 +38,8 @@
sobeloperator.cpp \
stats_scorer.cpp
+LOCAL_CFLAGS += -Wall -Wextra -Werror -Wno-unused-parameter
+
LOCAL_STATIC_LIBRARIES += \
libcutils
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/colorspace.cpp b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/colorspace.cpp
index 63e2ebf..ffb8003 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/colorspace.cpp
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/colorspace.cpp
@@ -65,9 +65,6 @@
uint8* pInV = pInput + size + size / 4;
Rgba* pOutColor = pOutput;
- const int u_offset = size;
- const int v_offset = u_offset + size / 4;
-
for (int y = 0; y < height; y += 2) {
for (int x = 0; x < width; x += 2) {
int u, v, y1, y2, y3, y4;
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/sobeloperator.cpp b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/sobeloperator.cpp
index dc5c305..808b90d 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/sobeloperator.cpp
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/jni/sobeloperator.cpp
@@ -81,8 +81,6 @@
short* gyPtr = new short[3 * numPixels];
computeGradient(srcPtr, width, height, gxPtr, gyPtr);
- unsigned char* mag = magPtr;
- unsigned char* dir = dirPtr;
for (int i = 0; i < numPixels; ++i) {
for (int c = 0; c < 3; c++) {
int gx = static_cast<int>(*(gxPtr + 3 * i + c) / 8 + 127.5);
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
index 5ecc770..702be49 100644
--- a/tests/SoundTriggerTestApp/res/layout/main.xml
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -66,6 +66,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dp"
+ android:checkedButton="@+id/model_one"
android:orientation="vertical">
<RadioButton android:id="@+id/model_one"
android:layout_width="wrap_content"
@@ -84,15 +85,21 @@
android:onClick="onRadioButtonClicked"/>
</RadioGroup>
- <TextView
- android:id="@+id/console"
- android:gravity="left"
+<ScrollView
+ android:id="@+id/scroller_id"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:fillViewport="true">
+
+ <TextView
+ android:id="@+id/console"
android:paddingTop="20pt"
android:layout_height="fill_parent"
- android:layout_width="match_parent"
- android:maxLines="40"
+ android:layout_width="fill_parent"
android:textSize="14dp"
- android:scrollbars = "vertical"
+ android:layout_weight="1.0"
android:text="@string/none">
</TextView>
+</ScrollView>
</LinearLayout>
diff --git a/tests/SoundTriggerTestApp/res/values/strings.xml b/tests/SoundTriggerTestApp/res/values/strings.xml
index 5f0fb1d..b4ca71b 100644
--- a/tests/SoundTriggerTestApp/res/values/strings.xml
+++ b/tests/SoundTriggerTestApp/res/values/strings.xml
@@ -24,5 +24,5 @@
<string name="model_one">Model One</string>
<string name="model_two">Model Two</string>
<string name="model_three">Model Three</string>
- <string name="none">Debug messages appear here:</string>
+ <string name="none">Debug messages appear here:\n</string>
</resources>
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
index 96a6966..3149783 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
@@ -32,6 +32,7 @@
import android.util.Log;
import android.view.View;
import android.widget.RadioButton;
+import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
@@ -52,6 +53,7 @@
private TextView mDebugView = null;
private int mSelectedModelId = 1;
+ private ScrollView mScrollView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -59,6 +61,7 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mDebugView = (TextView) findViewById(R.id.console);
+ mScrollView = (ScrollView) findViewById(R.id.scroller_id);
mDebugView.setText(mDebugView.getText(), TextView.BufferType.EDITABLE);
mDebugView.setMovementMethod(new ScrollingMovementMethod());
mSoundTriggerUtil = new SoundTriggerUtil(this);
@@ -68,6 +71,18 @@
private void postMessage(String msg) {
Log.i(TAG, "Posted: " + msg);
((Editable) mDebugView.getText()).append(msg + "\n");
+ if ((mDebugView.getMeasuredHeight() - mScrollView.getScrollY()) <=
+ (mScrollView.getHeight() + mDebugView.getLineHeight())) {
+ scrollToBottom();
+ }
+ }
+
+ private void scrollToBottom() {
+ mScrollView.post(new Runnable() {
+ public void run() {
+ mScrollView.smoothScrollTo(0, mDebugView.getBottom());
+ }
+ });
}
private UUID getSelectedUuid() {
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 46de201..9ac4dbf 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -162,78 +162,6 @@
}
},
- new Test("with topic Hello") {
- public void run() {
- Notification.BigTextStyle bigText = new Notification.BigTextStyle();
- bigText.bigText("FgBHreherhethethethe\ntwetwrterter\netetweterteryetry");
- Notification n = new Notification.Builder(NotificationTestList.this)
- .setSmallIcon(R.drawable.icon1)
- .setStyle(bigText)
- .setWhen(mActivityCreateTime)
- .setContentTitle("hihi")
- .setContentText("This is a notification!!!")
- .setContentIntent(makeIntent2())
- .setTopic(new Notification.Topic("hello", "Hello"))
- .build();
-
- mNM.notify(70, n);
- }
- },
-
- new Test("with topic GoodBye") {
- public void run() {
- Notification.BigPictureStyle picture = new Notification.BigPictureStyle();
- picture.bigPicture(BitmapFactory.decodeResource(getResources(),
- R.id.large_icon_pineapple2));
- Notification n = new Notification.Builder(NotificationTestList.this)
- .setSmallIcon(R.drawable.icon1)
- .setWhen(mActivityCreateTime)
- .setContentTitle("byebye")
- .setContentText("This is a notification!!!")
- .setContentIntent(makeIntent2())
- .setTopic(new Notification.Topic("bye", "Goodbye"))
- .setStyle(picture)
- .build();
-
- mNM.notify(71, n);
- }
- },
- new Test("with topic Bananas") {
- public void run() {
- Notification.BigTextStyle bigText = new Notification.BigTextStyle();
- bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
- Notification n = new Notification.Builder(NotificationTestList.this)
- .setSmallIcon(R.drawable.icon1)
- .setStyle(bigText)
- .setWhen(mActivityCreateTime)
- .setContentTitle("bananananana")
- .setContentText("This is a banana!!!")
- .setContentIntent(makeIntent2())
- .setTopic(new Notification.Topic("bananas", "Bananas"))
- .build();
-
- mNM.notify(72, n);
- }
- },
-
- new Test("with delete intent") {
- public void run() {
- Notification.BigTextStyle bigText = new Notification.BigTextStyle();
- bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
- Notification n = new Notification.Builder(NotificationTestList.this)
- .setSmallIcon(R.drawable.icon1)
- .setStyle(bigText)
- .setWhen(mActivityCreateTime)
- .setContentTitle("bananananana")
- .setContentText("This is a banana!!!")
- .setTopic(new Notification.Topic("bananas", "Bananas"))
- .setDeleteIntent(makeIntent2())
- .build();
-
- mNM.notify(73, n);
- }
- },
-
new Test("Is blocked?") {
public void run() {
Toast.makeText(NotificationTestList.this,
@@ -242,18 +170,10 @@
}
},
- new Test("Topic banana importance?") {
+ new Test("importance?") {
public void run() {
Toast.makeText(NotificationTestList.this,
- "bananas importance? " + mNM.getImportance("bananas"),
- Toast.LENGTH_LONG).show();
- }
- },
-
- new Test("Topic garbage importance?") {
- public void run() {
- Toast.makeText(NotificationTestList.this,
- "garbage importance? " + mNM.getImportance("garbage"),
+ "importance? " + mNM.getImportance(),
Toast.LENGTH_LONG).show();
}
},
diff --git a/tests/touchlag/Android.mk b/tests/touchlag/Android.mk
index 4f8aa1e..70b1989 100644
--- a/tests/touchlag/Android.mk
+++ b/tests/touchlag/Android.mk
@@ -9,6 +9,8 @@
LOCAL_MODULE:= test-touchlag
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)
diff --git a/tests/touchlag/touchlag.cpp b/tests/touchlag/touchlag.cpp
index df4befb..9264a25 100644
--- a/tests/touchlag/touchlag.cpp
+++ b/tests/touchlag/touchlag.cpp
@@ -54,11 +54,11 @@
void drawTwoPixels(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
if (y>0 && y<ssize_t(buf->h)) {
uint32_t* bits = buf->pixels + y * buf->s;
- if (x>=0 && x<buf->w) {
+ if (x>=0 && x<ssize_t(buf->w)) {
bits[x] = pixel;
}
ssize_t W(w);
- if ((x+W)>=0 && (x+W)<buf->w) {
+ if ((x+W)>=0 && (x+W)<ssize_t(buf->w)) {
bits[x+W] = pixel;
}
}
@@ -251,13 +251,13 @@
Queue queue;
- int x=0, y=0, down=0;
+ int x=0, y=0;
int lag_x=0, lag_y=0;
clearBuffer(&framebuffer, 0);
while (true) {
uint32_t crt = 0;
- int err = ioctl(fd, FBIO_WAITFORVSYNC, &crt);
+ ioctl(fd, FBIO_WAITFORVSYNC, &crt);
// draw beam marker
drawRect(&framebuffer, 0x400000, framebuffer.w-2, 0, 2, framebuffer.h);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 4b89217..17ab2ff5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1382,6 +1382,12 @@
}
@Override
+ public File getDataDir() {
+ // pass
+ return null;
+ }
+
+ @Override
public File getFilesDir() {
// pass
return null;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 189ecdc..9e390f6 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -308,6 +308,10 @@
"java.nio.charset.Charsets", "java.nio.charset.StandardCharsets",
"java.lang.IntegralToString", "com.android.tools.layoutlib.java.IntegralToString",
"java.lang.UnsafeByteSequence", "com.android.tools.layoutlib.java.UnsafeByteSequence",
+ // Use android.icu.text versions of DateFormat and SimpleDateFormat since the
+ // original ones do not match the Android implementation
+ "java.text.DateFormat", "android.icu.text.DateFormat",
+ "java.text.SimpleDateFormat", "android.icu.text.SimpleDateFormat"
};
private final static String[] EXCLUDED_CLASSES =
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 7f1ae24..59416b8 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -324,6 +324,11 @@
public int requestType;
/**
+ * Whether the secure RTT protocol needs to be used for ranging this peer device.
+ */
+ public boolean secure;
+
+ /**
* mac address of the device being ranged
* Default value: null
*/
@@ -478,6 +483,7 @@
for (RttParams params : mParams) {
dest.writeInt(params.deviceType);
dest.writeInt(params.requestType);
+ dest.writeByte(params.secure ? (byte) 1 : 0);
dest.writeString(params.bssid);
dest.writeInt(params.channelWidth);
dest.writeInt(params.frequency);
@@ -515,6 +521,7 @@
params[i] = new RttParams();
params[i].deviceType = in.readInt();
params[i].requestType = in.readInt();
+ params[i].secure = (in.readByte() != 0);
params[i].bssid = in.readString();
params[i].channelWidth = in.readInt();
params[i].frequency = in.readInt();
@@ -690,6 +697,11 @@
/** LCR information Element, only available to double side RTT. */
public WifiInformationElement LCR;
+
+ /**
+ * Whether the secure RTT protocol was used for ranging.
+ */
+ public boolean secure;
}
@@ -742,6 +754,7 @@
dest.writeInt((byte) result.LCR.data.length);
dest.writeByte(result.LCR.id);
}
+ dest.writeByte(result.secure ? (byte) 1 : 0);
}
} else {
dest.writeInt(0);
@@ -796,6 +809,7 @@
results[i].LCR.data = new byte[length];
in.readByteArray(results[i].LCR.data);
}
+ results[i].secure = (in.readByte() != 0);
}
ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 31da670..ed12bdf 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -331,6 +331,7 @@
*/
public static class InformationElement {
public static final int EID_SSID = 0;
+ public static final int EID_TIM = 5;
public static final int EID_BSS_LOAD = 11;
public static final int EID_RSN = 48;
public static final int EID_HT_OPERATION = 61;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index cce8386..ddd8f43 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -403,6 +403,15 @@
/**
* @hide
+ * The number of beacon intervals between Delivery Traffic Indication Maps (DTIM)
+ * This value is populated from scan results that contain Beacon Frames, which are infrequent.
+ * The value is not guaranteed to be set or current (Although it SHOULDNT change once set)
+ * Valid values are from 1 - 255. Initialized here as 0, use this to check if set.
+ */
+ public int dtimInterval = 0;
+
+ /**
+ * @hide
* Uid of app creating the configuration
*/
@SystemApi
@@ -1298,6 +1307,7 @@
lastUpdateUid = -1;
creatorUid = -1;
shared = true;
+ dtimInterval = 0;
}
/**
@@ -2044,4 +2054,4 @@
config.allowedKeyManagement.set(in.readInt());
return config;
}
-}
\ No newline at end of file
+}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 362738e..58e8761 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -20,6 +20,7 @@
import android.os.Parcelable;
import android.security.Credentials;
import android.text.TextUtils;
+import android.util.Log;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
@@ -116,10 +117,30 @@
public static final String CA_CERT_ALIAS_DELIMITER = " ";
+ // Fields to copy verbatim from wpa_supplicant.
+ private static final String[] SUPPLICANT_CONFIG_KEYS = new String[] {
+ IDENTITY_KEY,
+ ANON_IDENTITY_KEY,
+ PASSWORD_KEY,
+ CLIENT_CERT_KEY,
+ CA_CERT_KEY,
+ SUBJECT_MATCH_KEY,
+ ENGINE_KEY,
+ ENGINE_ID_KEY,
+ PRIVATE_KEY_ID_KEY,
+ ALTSUBJECT_MATCH_KEY,
+ DOM_SUFFIX_MATCH_KEY,
+ CA_PATH_KEY
+ };
+
private HashMap<String, String> mFields = new HashMap<String, String>();
private X509Certificate[] mCaCerts;
private PrivateKey mClientPrivateKey;
private X509Certificate mClientCertificate;
+ private int mEapMethod = Eap.NONE;
+ private int mPhase2Method = Phase2.NONE;
+
+ private static final String TAG = "WifiEnterpriseConfig";
public WifiEnterpriseConfig() {
// Do not set defaults so that the enterprise fields that are not changed
@@ -134,6 +155,8 @@
for (String key : source.mFields.keySet()) {
mFields.put(key, source.mFields.get(key));
}
+ mEapMethod = source.mEapMethod;
+ mPhase2Method = source.mPhase2Method;
}
@Override
@@ -149,6 +172,8 @@
dest.writeString(entry.getValue());
}
+ dest.writeInt(mEapMethod);
+ dest.writeInt(mPhase2Method);
writeCertificates(dest, mCaCerts);
if (mClientPrivateKey != null) {
@@ -200,6 +225,8 @@
enterpriseConfig.mFields.put(key, value);
}
+ enterpriseConfig.mEapMethod = in.readInt();
+ enterpriseConfig.mPhase2Method = in.readInt();
enterpriseConfig.mCaCerts = readCertificates(in);
PrivateKey userKey = null;
@@ -296,7 +323,8 @@
public static final int MSCHAPV2 = 3;
/** Generic Token Card */
public static final int GTC = 4;
- private static final String PREFIX = "auth=";
+ private static final String AUTH_PREFIX = "auth=";
+ private static final String AUTHEAP_PREFIX = "autheap=";
/** @hide */
public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP",
"MSCHAPV2", "GTC" };
@@ -305,11 +333,98 @@
private Phase2() {}
}
- /** Internal use only
+ // Loader and saver interfaces for exchanging data with wpa_supplicant.
+ // TODO: Decouple this object (which is just a placeholder of the configuration)
+ // from the implementation that knows what wpa_supplicant wants.
+ /**
+ * Interface used for retrieving supplicant configuration from WifiEnterpriseConfig
* @hide
*/
- public HashMap<String, String> getFields() {
- return mFields;
+ public interface SupplicantSaver {
+ /**
+ * Set a value within wpa_supplicant configuration
+ * @param key index to set within wpa_supplciant
+ * @param value the value for the key
+ * @return true if successful; false otherwise
+ */
+ boolean saveValue(String key, String value);
+ }
+
+ /**
+ * Interface used for populating a WifiEnterpriseConfig from supplicant configuration
+ * @hide
+ */
+ public interface SupplicantLoader {
+ /**
+ * Returns a value within wpa_supplicant configuration
+ * @param key index to set within wpa_supplciant
+ * @return string value if successful; null otherwise
+ */
+ String loadValue(String key);
+ }
+
+ /**
+ * Internal use only; supply field values to wpa_supplicant config. The configuration
+ * process aborts on the first failed call on {@code saver}.
+ * @param saver proxy for setting configuration in wpa_supplciant
+ * @return whether the save succeeded on all attempts
+ * @hide
+ */
+ public boolean saveToSupplicant(SupplicantSaver saver) {
+ if (!isEapMethodValid()) {
+ return false;
+ }
+
+ for (String key : mFields.keySet()) {
+ if (!saver.saveValue(key, mFields.get(key))) {
+ return false;
+ }
+ }
+
+ if (!saver.saveValue(EAP_KEY, Eap.strings[mEapMethod])) {
+ return false;
+ }
+
+ if (mEapMethod != Eap.TLS && mPhase2Method != Phase2.NONE) {
+ boolean is_autheap = mEapMethod == Eap.TTLS && mPhase2Method == Phase2.GTC;
+ String prefix = is_autheap ? Phase2.AUTHEAP_PREFIX : Phase2.AUTH_PREFIX;
+ String value = convertToQuotedString(prefix + Phase2.strings[mPhase2Method]);
+ return saver.saveValue(PHASE2_KEY, value);
+ } else if (mPhase2Method == Phase2.NONE) {
+ // By default, send a null phase 2 to clear old configuration values.
+ return saver.saveValue(PHASE2_KEY, null);
+ } else {
+ Log.e(TAG, "WiFi enterprise configuration is invalid as it supplies a "
+ + "phase 2 method but the phase1 method does not support it.");
+ return false;
+ }
+ }
+
+ /**
+ * Internal use only; retrieve configuration from wpa_supplicant config.
+ * @param loader proxy for retrieving configuration keys from wpa_supplicant
+ * @hide
+ */
+ public void loadFromSupplicant(SupplicantLoader loader) {
+ for (String key : SUPPLICANT_CONFIG_KEYS) {
+ String value = loader.loadValue(key);
+ if (value == null) {
+ mFields.put(key, EMPTY_VALUE);
+ } else {
+ mFields.put(key, value);
+ }
+ }
+ String eapMethod = loader.loadValue(EAP_KEY);
+ mEapMethod = getStringIndex(Eap.strings, eapMethod, Eap.NONE);
+
+ String phase2Method = removeDoubleQuotes(loader.loadValue(PHASE2_KEY));
+ // Remove "auth=" or "autheap=" prefix.
+ if (phase2Method.startsWith(Phase2.AUTH_PREFIX)) {
+ phase2Method = phase2Method.substring(Phase2.AUTH_PREFIX.length());
+ } else if (phase2Method.startsWith(Phase2.AUTHEAP_PREFIX)) {
+ phase2Method = phase2Method.substring(Phase2.AUTHEAP_PREFIX.length());
+ }
+ mPhase2Method = getStringIndex(Phase2.strings, phase2Method, Phase2.NONE);
}
/**
@@ -330,7 +445,7 @@
case Eap.SIM:
case Eap.AKA:
case Eap.AKA_PRIME:
- mFields.put(EAP_KEY, Eap.strings[eapMethod]);
+ mEapMethod = eapMethod;
mFields.put(OPP_KEY_CACHING, "1");
break;
default:
@@ -343,8 +458,7 @@
* @return eap method configured
*/
public int getEapMethod() {
- String eapMethod = mFields.get(EAP_KEY);
- return getStringIndex(Eap.strings, eapMethod, Eap.NONE);
+ return mEapMethod;
}
/**
@@ -359,15 +473,11 @@
public void setPhase2Method(int phase2Method) {
switch (phase2Method) {
case Phase2.NONE:
- mFields.put(PHASE2_KEY, EMPTY_VALUE);
- break;
- /** Valid methods */
case Phase2.PAP:
case Phase2.MSCHAP:
case Phase2.MSCHAPV2:
case Phase2.GTC:
- mFields.put(PHASE2_KEY, convertToQuotedString(
- Phase2.PREFIX + Phase2.strings[phase2Method]));
+ mPhase2Method = phase2Method;
break;
default:
throw new IllegalArgumentException("Unknown Phase 2 method");
@@ -379,12 +489,7 @@
* @return a phase 2 method defined at {@link Phase2}
* */
public int getPhase2Method() {
- String phase2Method = removeDoubleQuotes(mFields.get(PHASE2_KEY));
- // Remove auth= prefix
- if (phase2Method.startsWith(Phase2.PREFIX)) {
- phase2Method = phase2Method.substring(Phase2.PREFIX.length());
- }
- return getStringIndex(Phase2.strings, phase2Method, Phase2.NONE);
+ return mPhase2Method;
}
/**
@@ -412,7 +517,8 @@
setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity, "");
}
- /** Get the anonymous identity
+ /**
+ * Get the anonymous identity
* @return anonymous identity
*/
public String getAnonymousIdentity() {
@@ -839,18 +945,15 @@
}
/** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */
- String getKeyId(WifiEnterpriseConfig current) {
- String eap = mFields.get(EAP_KEY);
- String phase2 = mFields.get(PHASE2_KEY);
-
- // If either eap or phase2 are not initialized, use current config details
- if (TextUtils.isEmpty((eap))) {
- eap = current.mFields.get(EAP_KEY);
+ public String getKeyId(WifiEnterpriseConfig current) {
+ // If EAP method is not initialized, use current config details
+ if (mEapMethod == Eap.NONE) {
+ return (current != null) ? current.getKeyId(null) : EMPTY_VALUE;
}
- if (TextUtils.isEmpty(phase2)) {
- phase2 = current.mFields.get(PHASE2_KEY);
+ if (!isEapMethodValid()) {
+ return EMPTY_VALUE;
}
- return eap + "_" + phase2;
+ return Eap.strings[mEapMethod] + "_" + Phase2.strings[mPhase2Method];
}
private String removeDoubleQuotes(String string) {
@@ -867,7 +970,8 @@
return "\"" + string + "\"";
}
- /** Returns the index at which the toBeFound string is found in the array.
+ /**
+ * Returns the index at which the toBeFound string is found in the array.
* @param arr array of strings
* @param toBeFound string to be found
* @param defaultIndex default index to be returned when string is not found
@@ -881,13 +985,16 @@
return defaultIndex;
}
- /** Returns the field value for the key.
+ /**
+ * Returns the field value for the key.
* @param key into the hash
* @param prefix is the prefix that the value may have
* @return value
* @hide
*/
public String getFieldValue(String key, String prefix) {
+ // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
+ // neither of these keys should be retrieved in this manner.
String value = mFields.get(key);
// Uninitialized or known to be empty after reading from supplicant
if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return "";
@@ -900,13 +1007,16 @@
}
}
- /** Set a value with an optional prefix at key
+ /**
+ * Set a value with an optional prefix at key
* @param key into the hash
* @param value to be set
* @param prefix an optional value to be prefixed to actual value
* @hide
*/
public void setFieldValue(String key, String value, String prefix) {
+ // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
+ // neither of these keys should be set in this manner.
if (TextUtils.isEmpty(value)) {
mFields.put(key, EMPTY_VALUE);
} else {
@@ -915,13 +1025,16 @@
}
- /** Set a value with an optional prefix at key
+ /**
+ * Set a value with an optional prefix at key
* @param key into the hash
* @param value to be set
* @param prefix an optional value to be prefixed to actual value
* @hide
*/
public void setFieldValue(String key, String value) {
+ // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
+ // neither of these keys should be set in this manner.
if (TextUtils.isEmpty(value)) {
mFields.put(key, EMPTY_VALUE);
} else {
@@ -939,4 +1052,25 @@
}
return sb.toString();
}
+
+ /**
+ * Returns whether the EAP method data is valid, i.e., whether mEapMethod and mPhase2Method
+ * are valid indices into {@code Eap.strings[]} and {@code Phase2.strings[]} respectively.
+ */
+ private boolean isEapMethodValid() {
+ if (mEapMethod == Eap.NONE) {
+ Log.e(TAG, "WiFi enterprise configuration is invalid as it supplies no EAP method.");
+ return false;
+ }
+ if (mEapMethod < 0 || mEapMethod >= Eap.strings.length) {
+ Log.e(TAG, "mEapMethod is invald for WiFi enterprise configuration: " + mEapMethod);
+ return false;
+ }
+ if (mPhase2Method < 0 || mPhase2Method >= Phase2.strings.length) {
+ Log.e(TAG, "mPhase2Method is invald for WiFi enterprise configuration: "
+ + mPhase2Method);
+ return false;
+ }
+ return true;
+ }
}