Merge changes from topic 'mwd-merge-040115'
* changes:
Merge (manually) pag/209446: Increase allowed duration to connect to HOGP profile
Merge commit 'd91f193' into merge2
Merge commit '5718646' into merge2
Merge commit '7aa0345' into merge2
diff --git a/Android.mk b/Android.mk
index 2462d73..70e965b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -245,6 +245,7 @@
core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \
core/java/android/view/IApplicationToken.aidl \
core/java/android/view/IAssetAtlas.aidl \
+ core/java/android/view/IGraphicsStats.aidl \
core/java/android/view/IInputFilter.aidl \
core/java/android/view/IInputFilterHost.aidl \
core/java/android/view/IOnKeyguardExitResult.aidl \
diff --git a/api/current.txt b/api/current.txt
index 450e2d3..fb487ee 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -330,6 +330,7 @@
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
+ field public static final int autoVerify = 16844010; // 0x10104ea
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -353,6 +354,7 @@
field public static final int bottomRightRadius = 16843180; // 0x10101ac
field public static final int breadCrumbShortTitle = 16843524; // 0x1010304
field public static final int breadCrumbTitle = 16843523; // 0x1010303
+ field public static final int breakStrategy = 16844011; // 0x10104eb
field public static final int bufferType = 16843086; // 0x101014e
field public static final int button = 16843015; // 0x1010107
field public static final int buttonBarButtonStyle = 16843567; // 0x101032f
@@ -657,7 +659,7 @@
field public static final int headerDividersEnabled = 16843310; // 0x101022e
field public static final deprecated int headerMonthTextAppearance = 16843926; // 0x1010496
field public static final deprecated int headerTimeTextAppearance = 16843935; // 0x101049f
- field public static final int headerYearTextAppearance = 16843928; // 0x1010498
+ field public static final deprecated int headerYearTextAppearance = 16843928; // 0x1010498
field public static final int height = 16843093; // 0x1010155
field public static final int hideOnContentScroll = 16843843; // 0x1010443
field public static final int hint = 16843088; // 0x1010150
@@ -1456,7 +1458,7 @@
field public static final int x = 16842924; // 0x10100ac
field public static final int xlargeScreens = 16843455; // 0x10102bf
field public static final int y = 16842925; // 0x10100ad
- field public static final int yearListItemTextAppearance = 16843929; // 0x1010499
+ field public static final deprecated int yearListItemTextAppearance = 16843929; // 0x1010499
field public static final deprecated int yearListSelectorColor = 16843930; // 0x101049a
field public static final int yesNoPreferenceStyle = 16842896; // 0x1010090
field public static final int zAdjustment = 16843201; // 0x10101c1
@@ -2735,6 +2737,7 @@
}
public class AccountManager {
+ method public boolean accountAuthenticated(android.accounts.Account);
method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
@@ -2795,6 +2798,7 @@
field public static final java.lang.String KEY_ERROR_CODE = "errorCode";
field public static final java.lang.String KEY_ERROR_MESSAGE = "errorMessage";
field public static final java.lang.String KEY_INTENT = "intent";
+ field public static final java.lang.String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH = "lastAuthenticatedTimeMillisEpoch";
field public static final java.lang.String KEY_PASSWORD = "password";
field public static final java.lang.String KEY_USERDATA = "userdata";
field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
@@ -8253,6 +8257,8 @@
field public static final int NO_MATCH_CATEGORY = -4; // 0xfffffffc
field public static final int NO_MATCH_DATA = -2; // 0xfffffffe
field public static final int NO_MATCH_TYPE = -1; // 0xffffffff
+ field public static final java.lang.String SCHEME_HTTP = "http";
+ field public static final java.lang.String SCHEME_HTTPS = "https";
field public static final int SYSTEM_HIGH_PRIORITY = 1000; // 0x3e8
field public static final int SYSTEM_LOW_PRIORITY = -1000; // 0xfffffc18
}
@@ -8374,6 +8380,7 @@
ctor public RestrictionEntry(java.lang.String, boolean);
ctor public RestrictionEntry(java.lang.String, java.lang.String[]);
ctor public RestrictionEntry(java.lang.String, int);
+ ctor public RestrictionEntry(java.lang.String, android.content.RestrictionEntry[], boolean);
ctor public RestrictionEntry(android.os.Parcel);
method public int describeContents();
method public java.lang.String[] getAllSelectedStrings();
@@ -8382,6 +8389,7 @@
method public java.lang.String getDescription();
method public int getIntValue();
method public java.lang.String getKey();
+ method public android.content.RestrictionEntry[] getRestrictions();
method public boolean getSelectedState();
method public java.lang.String getSelectedString();
method public java.lang.String getTitle();
@@ -8393,6 +8401,7 @@
method public void setChoiceValues(android.content.Context, int);
method public void setDescription(java.lang.String);
method public void setIntValue(int);
+ method public void setRestrictions(android.content.RestrictionEntry[]);
method public void setSelectedState(boolean);
method public void setSelectedString(java.lang.String);
method public void setTitle(java.lang.String);
@@ -8400,6 +8409,8 @@
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR;
field public static final int TYPE_BOOLEAN = 1; // 0x1
+ field public static final int TYPE_BUNDLE = 7; // 0x7
+ field public static final int TYPE_BUNDLE_ARRAY = 8; // 0x8
field public static final int TYPE_CHOICE = 2; // 0x2
field public static final int TYPE_INTEGER = 5; // 0x5
field public static final int TYPE_MULTI_SELECT = 4; // 0x4
@@ -8408,6 +8419,7 @@
}
public class RestrictionsManager {
+ method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>);
method public android.content.Intent createLocalApprovalIntent();
method public android.os.Bundle getApplicationRestrictions();
method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String);
@@ -8832,6 +8844,25 @@
field public java.lang.String targetPackage;
}
+ public final class IntentFilterVerificationInfo implements android.os.Parcelable {
+ ctor public IntentFilterVerificationInfo();
+ ctor public IntentFilterVerificationInfo(java.lang.String, java.lang.String[]);
+ ctor public IntentFilterVerificationInfo(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ ctor public IntentFilterVerificationInfo(android.os.Parcel);
+ method public int describeContents();
+ method public java.lang.String[] getDomains();
+ method public java.lang.String getDomainsString();
+ method public java.lang.String getPackageName();
+ method public int getStatus();
+ method public java.lang.String getStatusString();
+ method public static java.lang.String getStatusStringFromValue(int);
+ method public void readFromXml(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public void setStatus(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ method public void writeToXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
+ field public static final android.os.Parcelable.Creator<android.content.pm.IntentFilterVerificationInfo> CREATOR;
+ }
+
public class LabeledIntent extends android.content.Intent {
ctor public LabeledIntent(android.content.Intent, java.lang.String, int, int);
ctor public LabeledIntent(android.content.Intent, java.lang.String, java.lang.CharSequence, int);
@@ -9060,6 +9091,7 @@
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public abstract java.lang.String getNameForUid(int);
@@ -11138,7 +11170,9 @@
field public static final int JPEG = 256; // 0x100
field public static final int NV16 = 16; // 0x10
field public static final int NV21 = 17; // 0x11
+ field public static final int PRIVATE = 34; // 0x22
field public static final int RAW10 = 37; // 0x25
+ field public static final int RAW12 = 38; // 0x26
field public static final int RAW_SENSOR = 32; // 0x20
field public static final int RGB_565 = 4; // 0x4
field public static final int UNKNOWN = 0; // 0x0
@@ -22512,6 +22546,7 @@
field public static java.lang.String DIRECTORY_RINGTONES;
field public static final java.lang.String MEDIA_BAD_REMOVAL = "bad_removal";
field public static final java.lang.String MEDIA_CHECKING = "checking";
+ field public static final java.lang.String MEDIA_EJECTING = "ejecting";
field public static final java.lang.String MEDIA_MOUNTED = "mounted";
field public static final java.lang.String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
field public static final java.lang.String MEDIA_NOFS = "nofs";
@@ -26826,6 +26861,7 @@
method public void ioReceive();
method public void ioSend();
method public deprecated synchronized void resize(int);
+ method public void setAutoPadding(boolean);
method public void setFromFieldPacker(int, android.renderscript.FieldPacker);
method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
method public void setFromFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
@@ -26925,6 +26961,10 @@
method public static android.renderscript.Element A_8(android.renderscript.RenderScript);
method public static android.renderscript.Element BOOLEAN(android.renderscript.RenderScript);
method public static android.renderscript.Element ELEMENT(android.renderscript.RenderScript);
+ method public static android.renderscript.Element F16(android.renderscript.RenderScript);
+ method public static android.renderscript.Element F16_2(android.renderscript.RenderScript);
+ method public static android.renderscript.Element F16_3(android.renderscript.RenderScript);
+ method public static android.renderscript.Element F16_4(android.renderscript.RenderScript);
method public static android.renderscript.Element F32(android.renderscript.RenderScript);
method public static android.renderscript.Element F32_2(android.renderscript.RenderScript);
method public static android.renderscript.Element F32_3(android.renderscript.RenderScript);
@@ -27023,6 +27063,7 @@
method public static android.renderscript.Element.DataType valueOf(java.lang.String);
method public static final android.renderscript.Element.DataType[] values();
enum_constant public static final android.renderscript.Element.DataType BOOLEAN;
+ enum_constant public static final android.renderscript.Element.DataType FLOAT_16;
enum_constant public static final android.renderscript.Element.DataType FLOAT_32;
enum_constant public static final android.renderscript.Element.DataType FLOAT_64;
enum_constant public static final android.renderscript.Element.DataType MATRIX_2X2;
@@ -27296,11 +27337,14 @@
method public static android.renderscript.RenderScript create(android.content.Context);
method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType);
method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, int);
+ method public static android.renderscript.RenderScript createMultiContext(android.content.Context, android.renderscript.RenderScript.ContextType, int, int);
method public void destroy();
method public void finish();
method public final android.content.Context getApplicationContext();
method public android.renderscript.RenderScript.RSErrorHandler getErrorHandler();
method public android.renderscript.RenderScript.RSMessageHandler getMessageHandler();
+ method public static long getMinorID();
+ method public static void releaseAllContexts();
method public void sendMessage(int, int[]);
method public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler);
method public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler);
@@ -27382,9 +27426,12 @@
public class Script extends android.renderscript.BaseObj {
method public void bindAllocation(android.renderscript.Allocation, int);
method protected android.renderscript.Script.FieldID createFieldID(int, android.renderscript.Element);
+ method protected android.renderscript.Script.InvokeID createInvokeID(int);
method protected android.renderscript.Script.KernelID createKernelID(int, int, android.renderscript.Element, android.renderscript.Element);
method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker);
method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions);
+ method protected void forEach(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.FieldPacker);
+ method protected void forEach(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions);
method public boolean getVarB(int);
method public double getVarD(int);
method public float getVarF(int);
@@ -27422,6 +27469,9 @@
public static final class Script.FieldID extends android.renderscript.BaseObj {
}
+ public static final class Script.InvokeID extends android.renderscript.BaseObj {
+ }
+
public static final class Script.KernelID extends android.renderscript.BaseObj {
}
@@ -27459,6 +27509,41 @@
method public android.renderscript.ScriptGroup create();
}
+ public class ScriptGroup2 extends android.renderscript.BaseObj {
+ ctor public ScriptGroup2(long, android.renderscript.RenderScript);
+ method public java.lang.Object[] execute(java.lang.Object...);
+ }
+
+ public static final class ScriptGroup2.Binding {
+ ctor public ScriptGroup2.Binding(android.renderscript.Script.FieldID, java.lang.Object);
+ method public android.renderscript.Script.FieldID getField();
+ method public java.lang.Object getValue();
+ }
+
+ public static final class ScriptGroup2.Builder {
+ ctor public ScriptGroup2.Builder(android.renderscript.RenderScript);
+ method public android.renderscript.ScriptGroup2.UnboundValue addInput();
+ method public android.renderscript.ScriptGroup2.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+ method public android.renderscript.ScriptGroup2.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object...);
+ method public android.renderscript.ScriptGroup2.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+ method public android.renderscript.ScriptGroup2.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object...);
+ method public android.renderscript.ScriptGroup2 create(android.renderscript.ScriptGroup2.Future...);
+ }
+
+ public static class ScriptGroup2.Closure extends android.renderscript.BaseObj {
+ ctor public ScriptGroup2.Closure(long, android.renderscript.RenderScript);
+ ctor public ScriptGroup2.Closure(android.renderscript.RenderScript, android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+ ctor public ScriptGroup2.Closure(android.renderscript.RenderScript, android.renderscript.Script.InvokeID, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+ method public android.renderscript.ScriptGroup2.Future getGlobal(android.renderscript.Script.FieldID);
+ method public android.renderscript.ScriptGroup2.Future getReturn();
+ }
+
+ public static class ScriptGroup2.Future {
+ }
+
+ public static class ScriptGroup2.UnboundValue {
+ }
+
public abstract class ScriptIntrinsic extends android.renderscript.Script {
}
@@ -27632,6 +27717,8 @@
method public static android.renderscript.Type createX(android.renderscript.RenderScript, android.renderscript.Element, int);
method public static android.renderscript.Type createXY(android.renderscript.RenderScript, android.renderscript.Element, int, int);
method public static android.renderscript.Type createXYZ(android.renderscript.RenderScript, android.renderscript.Element, int, int, int);
+ method public int getArray(int);
+ method public int getArrayCount();
method public int getCount();
method public android.renderscript.Element getElement();
method public int getX();
@@ -27645,6 +27732,7 @@
public static class Type.Builder {
ctor public Type.Builder(android.renderscript.RenderScript, android.renderscript.Element);
method public android.renderscript.Type create();
+ method public android.renderscript.Type.Builder setArray(int, int);
method public android.renderscript.Type.Builder setFaces(boolean);
method public android.renderscript.Type.Builder setMipmaps(boolean);
method public android.renderscript.Type.Builder setX(int);
@@ -30469,6 +30557,7 @@
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public java.lang.String getInstallerPackageName(java.lang.String);
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
@@ -30833,6 +30922,9 @@
method public final void increaseWidthTo(int);
method public boolean isRtlCharAt(int);
method protected final boolean isSpanned();
+ field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
+ field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
+ field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
}
@@ -34247,8 +34339,10 @@
method public long getTimeDelta();
method public boolean isInProgress();
method public boolean isQuickScaleEnabled();
+ method public boolean isSecondaryButtonScaleEnabled();
method public boolean onTouchEvent(android.view.MotionEvent);
method public void setQuickScaleEnabled(boolean);
+ method public void setSecondaryButtonScaleEnabled(boolean);
}
public static abstract interface ScaleGestureDetector.OnScaleGestureListener {
@@ -37777,7 +37871,6 @@
method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc
field public static final int ERROR_BAD_URL = -12; // 0xfffffff4
- field public static final int ERROR_BLOCKED = -16; // 0xfffffff0
field public static final int ERROR_CONNECT = -6; // 0xfffffffa
field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5
field public static final int ERROR_FILE = -13; // 0xfffffff3
@@ -38140,7 +38233,7 @@
field protected android.database.Cursor mDataCursor;
}
- public class AnalogClock extends android.view.View {
+ public deprecated class AnalogClock extends android.view.View {
ctor public AnalogClock(android.content.Context);
ctor public AnalogClock(android.content.Context, android.util.AttributeSet);
ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int);
@@ -39994,6 +40087,7 @@
method public void endBatchEdit();
method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
method public final int getAutoLinkMask();
+ method public int getBreakStrategy();
method public int getCompoundDrawablePadding();
method public android.content.res.ColorStateList getCompoundDrawableTintList();
method public android.graphics.PorterDuff.Mode getCompoundDrawableTintMode();
@@ -40095,6 +40189,7 @@
method public void removeTextChangedListener(android.text.TextWatcher);
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
+ method public void setBreakStrategy(int);
method public void setCompoundDrawablePadding(int);
method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
method public void setCompoundDrawableTintMode(android.graphics.PorterDuff.Mode);
@@ -40201,12 +40296,16 @@
ctor public TimePicker(android.content.Context, android.util.AttributeSet);
ctor public TimePicker(android.content.Context, android.util.AttributeSet, int);
ctor public TimePicker(android.content.Context, android.util.AttributeSet, int, int);
- method public java.lang.Integer getCurrentHour();
- method public java.lang.Integer getCurrentMinute();
+ method public deprecated java.lang.Integer getCurrentHour();
+ method public deprecated java.lang.Integer getCurrentMinute();
+ method public int getHour();
+ method public int getMinute();
method public boolean is24HourView();
- method public void setCurrentHour(java.lang.Integer);
- method public void setCurrentMinute(java.lang.Integer);
+ method public deprecated void setCurrentHour(java.lang.Integer);
+ method public deprecated void setCurrentMinute(java.lang.Integer);
+ method public void setHour(int);
method public void setIs24HourView(java.lang.Boolean);
+ method public void setMinute(int);
method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 6939cfc..84f9dbf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -103,6 +103,7 @@
field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
+ field public static final java.lang.String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
field public static final java.lang.String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
field public static final java.lang.String INTERNET = "android.permission.INTERNET";
@@ -134,6 +135,7 @@
field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
field public static final java.lang.String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
field public static final java.lang.String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
+ field public static final java.lang.String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
field public static final java.lang.String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
@@ -401,6 +403,7 @@
field public static final int autoStart = 16843445; // 0x10102b5
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
+ field public static final int autoVerify = 16844010; // 0x10104ea
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -424,6 +427,7 @@
field public static final int bottomRightRadius = 16843180; // 0x10101ac
field public static final int breadCrumbShortTitle = 16843524; // 0x1010304
field public static final int breadCrumbTitle = 16843523; // 0x1010303
+ field public static final int breakStrategy = 16844011; // 0x10104eb
field public static final int bufferType = 16843086; // 0x101014e
field public static final int button = 16843015; // 0x1010107
field public static final int buttonBarButtonStyle = 16843567; // 0x101032f
@@ -728,7 +732,7 @@
field public static final int headerDividersEnabled = 16843310; // 0x101022e
field public static final deprecated int headerMonthTextAppearance = 16843926; // 0x1010496
field public static final deprecated int headerTimeTextAppearance = 16843935; // 0x101049f
- field public static final int headerYearTextAppearance = 16843928; // 0x1010498
+ field public static final deprecated int headerYearTextAppearance = 16843928; // 0x1010498
field public static final int height = 16843093; // 0x1010155
field public static final int hideOnContentScroll = 16843843; // 0x1010443
field public static final int hint = 16843088; // 0x1010150
@@ -1531,7 +1535,7 @@
field public static final int x = 16842924; // 0x10100ac
field public static final int xlargeScreens = 16843455; // 0x10102bf
field public static final int y = 16842925; // 0x10100ad
- field public static final int yearListItemTextAppearance = 16843929; // 0x1010499
+ field public static final deprecated int yearListItemTextAppearance = 16843929; // 0x1010499
field public static final deprecated int yearListSelectorColor = 16843930; // 0x101049a
field public static final int yesNoPreferenceStyle = 16842896; // 0x1010090
field public static final int zAdjustment = 16843201; // 0x10101c1
@@ -2813,6 +2817,7 @@
}
public class AccountManager {
+ method public boolean accountAuthenticated(android.accounts.Account);
method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
@@ -2873,6 +2878,7 @@
field public static final java.lang.String KEY_ERROR_CODE = "errorCode";
field public static final java.lang.String KEY_ERROR_MESSAGE = "errorMessage";
field public static final java.lang.String KEY_INTENT = "intent";
+ field public static final java.lang.String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH = "lastAuthenticatedTimeMillisEpoch";
field public static final java.lang.String KEY_PASSWORD = "password";
field public static final java.lang.String KEY_USERDATA = "userdata";
field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
@@ -8177,6 +8183,7 @@
field public static final java.lang.String ACTION_INSERT = "android.intent.action.INSERT";
field public static final java.lang.String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT";
field public static final java.lang.String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE";
+ field public static final java.lang.String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
field public static final java.lang.String ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED";
field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED";
@@ -8474,6 +8481,8 @@
field public static final int NO_MATCH_CATEGORY = -4; // 0xfffffffc
field public static final int NO_MATCH_DATA = -2; // 0xfffffffe
field public static final int NO_MATCH_TYPE = -1; // 0xffffffff
+ field public static final java.lang.String SCHEME_HTTP = "http";
+ field public static final java.lang.String SCHEME_HTTPS = "https";
field public static final int SYSTEM_HIGH_PRIORITY = 1000; // 0x3e8
field public static final int SYSTEM_LOW_PRIORITY = -1000; // 0xfffffc18
}
@@ -8595,6 +8604,7 @@
ctor public RestrictionEntry(java.lang.String, boolean);
ctor public RestrictionEntry(java.lang.String, java.lang.String[]);
ctor public RestrictionEntry(java.lang.String, int);
+ ctor public RestrictionEntry(java.lang.String, android.content.RestrictionEntry[], boolean);
ctor public RestrictionEntry(android.os.Parcel);
method public int describeContents();
method public java.lang.String[] getAllSelectedStrings();
@@ -8603,6 +8613,7 @@
method public java.lang.String getDescription();
method public int getIntValue();
method public java.lang.String getKey();
+ method public android.content.RestrictionEntry[] getRestrictions();
method public boolean getSelectedState();
method public java.lang.String getSelectedString();
method public java.lang.String getTitle();
@@ -8614,6 +8625,7 @@
method public void setChoiceValues(android.content.Context, int);
method public void setDescription(java.lang.String);
method public void setIntValue(int);
+ method public void setRestrictions(android.content.RestrictionEntry[]);
method public void setSelectedState(boolean);
method public void setSelectedString(java.lang.String);
method public void setTitle(java.lang.String);
@@ -8621,6 +8633,8 @@
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR;
field public static final int TYPE_BOOLEAN = 1; // 0x1
+ field public static final int TYPE_BUNDLE = 7; // 0x7
+ field public static final int TYPE_BUNDLE_ARRAY = 8; // 0x8
field public static final int TYPE_CHOICE = 2; // 0x2
field public static final int TYPE_INTEGER = 5; // 0x5
field public static final int TYPE_MULTI_SELECT = 4; // 0x4
@@ -8629,6 +8643,7 @@
}
public class RestrictionsManager {
+ method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>);
method public android.content.Intent createLocalApprovalIntent();
method public android.os.Bundle getApplicationRestrictions();
method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String);
@@ -9072,6 +9087,25 @@
field public java.lang.String targetPackage;
}
+ public final class IntentFilterVerificationInfo implements android.os.Parcelable {
+ ctor public IntentFilterVerificationInfo();
+ ctor public IntentFilterVerificationInfo(java.lang.String, java.lang.String[]);
+ ctor public IntentFilterVerificationInfo(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ ctor public IntentFilterVerificationInfo(android.os.Parcel);
+ method public int describeContents();
+ method public java.lang.String[] getDomains();
+ method public java.lang.String getDomainsString();
+ method public java.lang.String getPackageName();
+ method public int getStatus();
+ method public java.lang.String getStatusString();
+ method public static java.lang.String getStatusStringFromValue(int);
+ method public void readFromXml(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public void setStatus(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ method public void writeToXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
+ field public static final android.os.Parcelable.Creator<android.content.pm.IntentFilterVerificationInfo> CREATOR;
+ }
+
public class LabeledIntent extends android.content.Intent {
ctor public LabeledIntent(android.content.Intent, java.lang.String, int, int);
ctor public LabeledIntent(android.content.Intent, java.lang.String, java.lang.CharSequence, int);
@@ -9306,6 +9340,7 @@
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public abstract java.lang.String getNameForUid(int);
@@ -11424,7 +11459,9 @@
field public static final int JPEG = 256; // 0x100
field public static final int NV16 = 16; // 0x10
field public static final int NV21 = 17; // 0x11
+ field public static final int PRIVATE = 34; // 0x22
field public static final int RAW10 = 37; // 0x25
+ field public static final int RAW12 = 38; // 0x26
field public static final int RAW_SENSOR = 32; // 0x20
field public static final int RGB_565 = 4; // 0x4
field public static final int UNKNOWN = 0; // 0x0
@@ -14174,6 +14211,7 @@
method public void setHdmiMhlVendorCommandListener(android.hardware.hdmi.HdmiTvClient.HdmiMhlVendorCommandListener);
method public void setInputChangeListener(android.hardware.hdmi.HdmiTvClient.InputChangeListener);
method public void setRecordListener(android.hardware.hdmi.HdmiRecordListener);
+ method public void setSystemAudioMode(boolean, android.hardware.hdmi.HdmiTvClient.SelectCallback);
method public void setSystemAudioMute(boolean);
method public void setSystemAudioVolume(int, int, int);
method public void startOneTouchRecord(int, android.hardware.hdmi.HdmiRecordSources.RecordSource);
@@ -24375,6 +24413,7 @@
field public static java.lang.String DIRECTORY_RINGTONES;
field public static final java.lang.String MEDIA_BAD_REMOVAL = "bad_removal";
field public static final java.lang.String MEDIA_CHECKING = "checking";
+ field public static final java.lang.String MEDIA_EJECTING = "ejecting";
field public static final java.lang.String MEDIA_MOUNTED = "mounted";
field public static final java.lang.String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
field public static final java.lang.String MEDIA_NOFS = "nofs";
@@ -27891,6 +27930,108 @@
field public static final java.lang.String SIZE = "_size";
}
+ public abstract class SearchIndexableData {
+ ctor public SearchIndexableData();
+ ctor public SearchIndexableData(android.content.Context);
+ field public java.lang.String className;
+ field public android.content.Context context;
+ field public boolean enabled;
+ field public int iconResId;
+ field public java.lang.String intentAction;
+ field public java.lang.String intentTargetClass;
+ field public java.lang.String intentTargetPackage;
+ field public java.lang.String key;
+ field public java.util.Locale locale;
+ field public java.lang.String packageName;
+ field public int rank;
+ field public int userId;
+ }
+
+ public class SearchIndexableResource extends android.provider.SearchIndexableData {
+ ctor public SearchIndexableResource(int, int, java.lang.String, int);
+ ctor public SearchIndexableResource(android.content.Context);
+ field public int xmlResId;
+ }
+
+ public class SearchIndexablesContract {
+ ctor public SearchIndexablesContract();
+ field public static final int COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE = 0; // 0x0
+ field public static final int COLUMN_INDEX_RAW_CLASS_NAME = 7; // 0x7
+ field public static final int COLUMN_INDEX_RAW_ENTRIES = 4; // 0x4
+ field public static final int COLUMN_INDEX_RAW_ICON_RESID = 8; // 0x8
+ field public static final int COLUMN_INDEX_RAW_INTENT_ACTION = 9; // 0x9
+ field public static final int COLUMN_INDEX_RAW_INTENT_TARGET_CLASS = 11; // 0xb
+ field public static final int COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE = 10; // 0xa
+ field public static final int COLUMN_INDEX_RAW_KEY = 12; // 0xc
+ field public static final int COLUMN_INDEX_RAW_KEYWORDS = 5; // 0x5
+ field public static final int COLUMN_INDEX_RAW_RANK = 0; // 0x0
+ field public static final int COLUMN_INDEX_RAW_SCREEN_TITLE = 6; // 0x6
+ field public static final int COLUMN_INDEX_RAW_SUMMARY_OFF = 3; // 0x3
+ field public static final int COLUMN_INDEX_RAW_SUMMARY_ON = 2; // 0x2
+ field public static final int COLUMN_INDEX_RAW_TITLE = 1; // 0x1
+ field public static final int COLUMN_INDEX_RAW_USER_ID = 13; // 0xd
+ field public static final int COLUMN_INDEX_XML_RES_CLASS_NAME = 2; // 0x2
+ field public static final int COLUMN_INDEX_XML_RES_ICON_RESID = 3; // 0x3
+ field public static final int COLUMN_INDEX_XML_RES_INTENT_ACTION = 4; // 0x4
+ field public static final int COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS = 6; // 0x6
+ field public static final int COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE = 5; // 0x5
+ field public static final int COLUMN_INDEX_XML_RES_RANK = 0; // 0x0
+ field public static final int COLUMN_INDEX_XML_RES_RESID = 1; // 0x1
+ field public static final java.lang.String INDEXABLES_RAW = "indexables_raw";
+ field public static final java.lang.String[] INDEXABLES_RAW_COLUMNS;
+ field public static final java.lang.String INDEXABLES_RAW_PATH = "settings/indexables_raw";
+ field public static final java.lang.String INDEXABLES_XML_RES = "indexables_xml_res";
+ field public static final java.lang.String[] INDEXABLES_XML_RES_COLUMNS;
+ field public static final java.lang.String INDEXABLES_XML_RES_PATH = "settings/indexables_xml_res";
+ field public static final java.lang.String NON_INDEXABLES_KEYS = "non_indexables_key";
+ field public static final java.lang.String[] NON_INDEXABLES_KEYS_COLUMNS;
+ field public static final java.lang.String NON_INDEXABLES_KEYS_PATH = "settings/non_indexables_key";
+ field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.SEARCH_INDEXABLES_PROVIDER";
+ }
+
+ public static class SearchIndexablesContract.BaseColumns {
+ field public static final java.lang.String COLUMN_CLASS_NAME = "className";
+ field public static final java.lang.String COLUMN_ICON_RESID = "iconResId";
+ field public static final java.lang.String COLUMN_INTENT_ACTION = "intentAction";
+ field public static final java.lang.String COLUMN_INTENT_TARGET_CLASS = "intentTargetClass";
+ field public static final java.lang.String COLUMN_INTENT_TARGET_PACKAGE = "intentTargetPackage";
+ field public static final java.lang.String COLUMN_RANK = "rank";
+ }
+
+ public static final class SearchIndexablesContract.NonIndexableKey extends android.provider.SearchIndexablesContract.BaseColumns {
+ field public static final java.lang.String COLUMN_KEY_VALUE = "key";
+ field public static final java.lang.String MIME_TYPE = "vnd.android.cursor.dir/non_indexables_key";
+ }
+
+ public static final class SearchIndexablesContract.RawData extends android.provider.SearchIndexablesContract.BaseColumns {
+ field public static final java.lang.String COLUMN_ENTRIES = "entries";
+ field public static final java.lang.String COLUMN_KEY = "key";
+ field public static final java.lang.String COLUMN_KEYWORDS = "keywords";
+ field public static final java.lang.String COLUMN_SCREEN_TITLE = "screenTitle";
+ field public static final java.lang.String COLUMN_SUMMARY_OFF = "summaryOff";
+ field public static final java.lang.String COLUMN_SUMMARY_ON = "summaryOn";
+ field public static final java.lang.String COLUMN_TITLE = "title";
+ field public static final java.lang.String COLUMN_USER_ID = "user_id";
+ field public static final java.lang.String MIME_TYPE = "vnd.android.cursor.dir/indexables_raw";
+ }
+
+ public static final class SearchIndexablesContract.XmlResource extends android.provider.SearchIndexablesContract.BaseColumns {
+ field public static final java.lang.String COLUMN_XML_RESID = "xmlResId";
+ field public static final java.lang.String MIME_TYPE = "vnd.android.cursor.dir/indexables_xml_res";
+ }
+
+ public abstract class SearchIndexablesProvider extends android.content.ContentProvider {
+ ctor public SearchIndexablesProvider();
+ method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+ method public java.lang.String getType(android.net.Uri);
+ method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+ method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public abstract android.database.Cursor queryNonIndexableKeys(java.lang.String[]);
+ method public abstract android.database.Cursor queryRawData(java.lang.String[]);
+ method public abstract android.database.Cursor queryXmlResources(java.lang.String[]);
+ method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+ }
+
public class SearchRecentSuggestions {
ctor public SearchRecentSuggestions(android.content.Context, java.lang.String, int);
method public void clearHistory();
@@ -28702,6 +28843,7 @@
method public void ioReceive();
method public void ioSend();
method public deprecated synchronized void resize(int);
+ method public void setAutoPadding(boolean);
method public void setFromFieldPacker(int, android.renderscript.FieldPacker);
method public void setFromFieldPacker(int, int, android.renderscript.FieldPacker);
method public void setFromFieldPacker(int, int, int, int, android.renderscript.FieldPacker);
@@ -28801,6 +28943,10 @@
method public static android.renderscript.Element A_8(android.renderscript.RenderScript);
method public static android.renderscript.Element BOOLEAN(android.renderscript.RenderScript);
method public static android.renderscript.Element ELEMENT(android.renderscript.RenderScript);
+ method public static android.renderscript.Element F16(android.renderscript.RenderScript);
+ method public static android.renderscript.Element F16_2(android.renderscript.RenderScript);
+ method public static android.renderscript.Element F16_3(android.renderscript.RenderScript);
+ method public static android.renderscript.Element F16_4(android.renderscript.RenderScript);
method public static android.renderscript.Element F32(android.renderscript.RenderScript);
method public static android.renderscript.Element F32_2(android.renderscript.RenderScript);
method public static android.renderscript.Element F32_3(android.renderscript.RenderScript);
@@ -28899,6 +29045,7 @@
method public static android.renderscript.Element.DataType valueOf(java.lang.String);
method public static final android.renderscript.Element.DataType[] values();
enum_constant public static final android.renderscript.Element.DataType BOOLEAN;
+ enum_constant public static final android.renderscript.Element.DataType FLOAT_16;
enum_constant public static final android.renderscript.Element.DataType FLOAT_32;
enum_constant public static final android.renderscript.Element.DataType FLOAT_64;
enum_constant public static final android.renderscript.Element.DataType MATRIX_2X2;
@@ -29172,11 +29319,14 @@
method public static android.renderscript.RenderScript create(android.content.Context);
method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType);
method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, int);
+ method public static android.renderscript.RenderScript createMultiContext(android.content.Context, android.renderscript.RenderScript.ContextType, int, int);
method public void destroy();
method public void finish();
method public final android.content.Context getApplicationContext();
method public android.renderscript.RenderScript.RSErrorHandler getErrorHandler();
method public android.renderscript.RenderScript.RSMessageHandler getMessageHandler();
+ method public static long getMinorID();
+ method public static void releaseAllContexts();
method public void sendMessage(int, int[]);
method public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler);
method public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler);
@@ -29258,9 +29408,12 @@
public class Script extends android.renderscript.BaseObj {
method public void bindAllocation(android.renderscript.Allocation, int);
method protected android.renderscript.Script.FieldID createFieldID(int, android.renderscript.Element);
+ method protected android.renderscript.Script.InvokeID createInvokeID(int);
method protected android.renderscript.Script.KernelID createKernelID(int, int, android.renderscript.Element, android.renderscript.Element);
method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker);
method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions);
+ method protected void forEach(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.FieldPacker);
+ method protected void forEach(int, android.renderscript.Allocation[], android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions);
method public boolean getVarB(int);
method public double getVarD(int);
method public float getVarF(int);
@@ -29298,6 +29451,9 @@
public static final class Script.FieldID extends android.renderscript.BaseObj {
}
+ public static final class Script.InvokeID extends android.renderscript.BaseObj {
+ }
+
public static final class Script.KernelID extends android.renderscript.BaseObj {
}
@@ -29335,6 +29491,41 @@
method public android.renderscript.ScriptGroup create();
}
+ public class ScriptGroup2 extends android.renderscript.BaseObj {
+ ctor public ScriptGroup2(long, android.renderscript.RenderScript);
+ method public java.lang.Object[] execute(java.lang.Object...);
+ }
+
+ public static final class ScriptGroup2.Binding {
+ ctor public ScriptGroup2.Binding(android.renderscript.Script.FieldID, java.lang.Object);
+ method public android.renderscript.Script.FieldID getField();
+ method public java.lang.Object getValue();
+ }
+
+ public static final class ScriptGroup2.Builder {
+ ctor public ScriptGroup2.Builder(android.renderscript.RenderScript);
+ method public android.renderscript.ScriptGroup2.UnboundValue addInput();
+ method public android.renderscript.ScriptGroup2.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+ method public android.renderscript.ScriptGroup2.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object...);
+ method public android.renderscript.ScriptGroup2.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+ method public android.renderscript.ScriptGroup2.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object...);
+ method public android.renderscript.ScriptGroup2 create(android.renderscript.ScriptGroup2.Future...);
+ }
+
+ public static class ScriptGroup2.Closure extends android.renderscript.BaseObj {
+ ctor public ScriptGroup2.Closure(long, android.renderscript.RenderScript);
+ ctor public ScriptGroup2.Closure(android.renderscript.RenderScript, android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+ ctor public ScriptGroup2.Closure(android.renderscript.RenderScript, android.renderscript.Script.InvokeID, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+ method public android.renderscript.ScriptGroup2.Future getGlobal(android.renderscript.Script.FieldID);
+ method public android.renderscript.ScriptGroup2.Future getReturn();
+ }
+
+ public static class ScriptGroup2.Future {
+ }
+
+ public static class ScriptGroup2.UnboundValue {
+ }
+
public abstract class ScriptIntrinsic extends android.renderscript.Script {
}
@@ -29508,6 +29699,8 @@
method public static android.renderscript.Type createX(android.renderscript.RenderScript, android.renderscript.Element, int);
method public static android.renderscript.Type createXY(android.renderscript.RenderScript, android.renderscript.Element, int, int);
method public static android.renderscript.Type createXYZ(android.renderscript.RenderScript, android.renderscript.Element, int, int, int);
+ method public int getArray(int);
+ method public int getArrayCount();
method public int getCount();
method public android.renderscript.Element getElement();
method public int getX();
@@ -29521,6 +29714,7 @@
public static class Type.Builder {
ctor public Type.Builder(android.renderscript.RenderScript, android.renderscript.Element);
method public android.renderscript.Type create();
+ method public android.renderscript.Type.Builder setArray(int, int);
method public android.renderscript.Type.Builder setFaces(boolean);
method public android.renderscript.Type.Builder setMipmaps(boolean);
method public android.renderscript.Type.Builder setX(int);
@@ -32906,6 +33100,7 @@
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public java.lang.String getInstallerPackageName(java.lang.String);
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
@@ -33272,6 +33467,9 @@
method public final void increaseWidthTo(int);
method public boolean isRtlCharAt(int);
method protected final boolean isSpanned();
+ field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
+ field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
+ field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
}
@@ -36686,8 +36884,10 @@
method public long getTimeDelta();
method public boolean isInProgress();
method public boolean isQuickScaleEnabled();
+ method public boolean isSecondaryButtonScaleEnabled();
method public boolean onTouchEvent(android.view.MotionEvent);
method public void setQuickScaleEnabled(boolean);
+ method public void setSecondaryButtonScaleEnabled(boolean);
}
public static abstract interface ScaleGestureDetector.OnScaleGestureListener {
@@ -40322,7 +40522,6 @@
method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc
field public static final int ERROR_BAD_URL = -12; // 0xfffffff4
- field public static final int ERROR_BLOCKED = -16; // 0xfffffff0
field public static final int ERROR_CONNECT = -6; // 0xfffffffa
field public static final int ERROR_FAILED_SSL_HANDSHAKE = -11; // 0xfffffff5
field public static final int ERROR_FILE = -13; // 0xfffffff3
@@ -40880,7 +41079,7 @@
field protected android.database.Cursor mDataCursor;
}
- public class AnalogClock extends android.view.View {
+ public deprecated class AnalogClock extends android.view.View {
ctor public AnalogClock(android.content.Context);
ctor public AnalogClock(android.content.Context, android.util.AttributeSet);
ctor public AnalogClock(android.content.Context, android.util.AttributeSet, int);
@@ -42734,6 +42933,7 @@
method public void endBatchEdit();
method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
method public final int getAutoLinkMask();
+ method public int getBreakStrategy();
method public int getCompoundDrawablePadding();
method public android.content.res.ColorStateList getCompoundDrawableTintList();
method public android.graphics.PorterDuff.Mode getCompoundDrawableTintMode();
@@ -42835,6 +43035,7 @@
method public void removeTextChangedListener(android.text.TextWatcher);
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
+ method public void setBreakStrategy(int);
method public void setCompoundDrawablePadding(int);
method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
method public void setCompoundDrawableTintMode(android.graphics.PorterDuff.Mode);
@@ -42941,12 +43142,16 @@
ctor public TimePicker(android.content.Context, android.util.AttributeSet);
ctor public TimePicker(android.content.Context, android.util.AttributeSet, int);
ctor public TimePicker(android.content.Context, android.util.AttributeSet, int, int);
- method public java.lang.Integer getCurrentHour();
- method public java.lang.Integer getCurrentMinute();
+ method public deprecated java.lang.Integer getCurrentHour();
+ method public deprecated java.lang.Integer getCurrentMinute();
+ method public int getHour();
+ method public int getMinute();
method public boolean is24HourView();
- method public void setCurrentHour(java.lang.Integer);
- method public void setCurrentMinute(java.lang.Integer);
+ method public deprecated void setCurrentHour(java.lang.Integer);
+ method public deprecated void setCurrentMinute(java.lang.Integer);
+ method public void setHour(int);
method public void setIs24HourView(java.lang.Boolean);
+ method public void setMinute(int);
method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
}
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index c86fd53..c5af992 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -7,6 +7,12 @@
#define LOG_TAG "appproc"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <utils/Log.h>
@@ -17,11 +23,6 @@
#include <android_runtime/AndroidRuntime.h>
#include <private/android_filesystem_config.h> // for AID_SYSTEM
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/prctl.h>
-
namespace android {
static void app_usage()
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index 197e36b..84158d3 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -1,3 +1,6 @@
+#include <dirent.h>
+#include <sys/stat.h>
+
#include "idmap.h"
#include <UniquePtr.h>
@@ -9,8 +12,6 @@
#include <utils/String16.h>
#include <utils/String8.h>
-#include <dirent.h>
-
#define NO_OVERLAY_TAG (-1000)
using namespace android;
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 6957435c..480d171 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -203,6 +203,14 @@
public static final String KEY_USERDATA = "userdata";
/**
+ * Bundle key used to supply the last time the credentials of the account
+ * were authenticated successfully. Time is specified in milliseconds since
+ * epoch.
+ */
+ public static final String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH =
+ "lastAuthenticatedTimeMillisEpoch";
+
+ /**
* Authenticators using 'customTokens' option will also get the UID of the
* caller
*/
@@ -663,6 +671,31 @@
}
/**
+ * Informs the system that the account has been authenticated recently. This
+ * recency may be used by other applications to verify the account. This
+ * should be called only when the user has entered correct credentials for
+ * the account.
+ * <p>
+ * It is not safe to call this method from the main thread. As such, call it
+ * from another thread.
+ * <p>
+ * This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and should be
+ * called from the account's authenticator.
+ *
+ * @param account The {@link Account} to be updated.
+ */
+ public boolean accountAuthenticated(Account account) {
+ if (account == null)
+ throw new IllegalArgumentException("account is null");
+ try {
+ return mService.accountAuthenticated(account);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* Rename the specified {@link Account}. This is equivalent to removing
* the existing account and adding a new renamed account with the old
* account's user data.
@@ -1544,15 +1577,20 @@
* with these fields if activity or password was supplied and
* the account was successfully verified:
* <ul>
- * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
+ * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account verified
* <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
* <li> {@link #KEY_BOOLEAN_RESULT} - true to indicate success
* </ul>
*
* If no activity or password was specified, the returned Bundle contains
- * only {@link #KEY_INTENT} with the {@link Intent} needed to launch the
- * password prompt. If an error occurred,
- * {@link AccountManagerFuture#getResult()} throws:
+ * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
+ * password prompt.
+ *
+ * <p>Also the returning Bundle may contain {@link
+ * #KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH} indicating the last time the
+ * credential was validated/created.
+ *
+ * If an error occurred,{@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if the authenticator failed to respond
* <li> {@link OperationCanceledException} if the operation was canceled for
@@ -1625,9 +1663,9 @@
* <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
* </ul>
*
- * If no activity was specified, the returned Bundle contains only
+ * If no activity was specified, the returned Bundle contains
* {@link #KEY_INTENT} with the {@link Intent} needed to launch the
- * password prompt. If an error occurred,
+ * password prompt. If an error occurred,
* {@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if the authenticator failed to respond
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index aa41161..04b3c88 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -67,6 +67,7 @@
boolean expectActivityLaunch);
void confirmCredentialsAsUser(in IAccountManagerResponse response, in Account account,
in Bundle options, boolean expectActivityLaunch, int userId);
+ boolean accountAuthenticated(in Account account);
void getAuthTokenLabel(in IAccountManagerResponse response, String accountType,
String authTokenType);
diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java
index 56da940..0173079 100644
--- a/core/java/android/animation/FloatKeyframeSet.java
+++ b/core/java/android/animation/FloatKeyframeSet.java
@@ -118,13 +118,14 @@
FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
if (fraction < nextKeyframe.getFraction()) {
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
- if (interpolator != null) {
- fraction = interpolator.getInterpolation(fraction);
- }
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
float prevValue = prevKeyframe.getFloatValue();
float nextValue = nextKeyframe.getFloatValue();
+ // Apply interpolator on the proportional duration.
+ if (interpolator != null) {
+ intervalFraction = interpolator.getInterpolation(intervalFraction);
+ }
return mEvaluator == null ?
prevValue + intervalFraction * (nextValue - prevValue) :
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java
index 12a4bf9..73f9af1 100644
--- a/core/java/android/animation/IntKeyframeSet.java
+++ b/core/java/android/animation/IntKeyframeSet.java
@@ -117,13 +117,14 @@
IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i);
if (fraction < nextKeyframe.getFraction()) {
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
- if (interpolator != null) {
- fraction = interpolator.getInterpolation(fraction);
- }
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
int prevValue = prevKeyframe.getIntValue();
int nextValue = nextKeyframe.getIntValue();
+ // Apply interpolator on the proportional duration.
+ if (interpolator != null) {
+ intervalFraction = interpolator.getInterpolation(intervalFraction);
+ }
return mEvaluator == null ?
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index c80e162..32edd4d 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -201,7 +201,6 @@
* @return The animated value.
*/
public Object getValue(float fraction) {
-
// Special-case optimization for the common case of only two keyframes
if (mNumKeyframes == 2) {
if (mInterpolator != null) {
@@ -238,12 +237,13 @@
Keyframe nextKeyframe = mKeyframes.get(i);
if (fraction < nextKeyframe.getFraction()) {
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
- if (interpolator != null) {
- fraction = interpolator.getInterpolation(fraction);
- }
final float prevFraction = prevKeyframe.getFraction();
float intervalFraction = (fraction - prevFraction) /
(nextKeyframe.getFraction() - prevFraction);
+ // Apply interpolator on the proportional duration.
+ if (interpolator != null) {
+ intervalFraction = interpolator.getInterpolation(intervalFraction);
+ }
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
nextKeyframe.getValue());
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4880db1..81b1583 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -254,18 +254,21 @@
}
}
+ static final class AcquiringProviderRecord {
+ IActivityManager.ContentProviderHolder holder;
+ boolean acquiring = true;
+ int requests = 1;
+ }
+
// The lock of mProviderMap protects the following variables.
- final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
- = new ArrayMap<ProviderKey, ProviderClientRecord>();
- final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
- = new ArrayMap<IBinder, ProviderRefCount>();
- final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
- = new ArrayMap<IBinder, ProviderClientRecord>();
- final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
- = new ArrayMap<ComponentName, ProviderClientRecord>();
+ final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<>();
+ final ArrayMap<ProviderKey, AcquiringProviderRecord> mAcquiringProviderMap = new ArrayMap<>();
+ final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap = new ArrayMap<>();
+ final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders = new ArrayMap<>();
+ final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName = new ArrayMap<>();
final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
- = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
+ = new ArrayMap<>();
final GcIdler mGcIdler = new GcIdler();
boolean mGcIdlerScheduled = false;
@@ -345,7 +348,7 @@
}
}
- final class ProviderClientRecord {
+ static final class ProviderClientRecord {
final String[] mNames;
final IContentProvider mProvider;
final ContentProvider mLocalProvider;
@@ -4693,22 +4696,57 @@
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
- final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
+ final ProviderKey key = new ProviderKey(auth, userId);
+ final IContentProvider provider = acquireExistingProvider(c, key, stable);
if (provider != null) {
return provider;
}
+ AcquiringProviderRecord r;
+ boolean first = false;
+ synchronized (mAcquiringProviderMap) {
+ r = mAcquiringProviderMap.get(key);
+ if (r == null) {
+ r = new AcquiringProviderRecord();
+ mAcquiringProviderMap.put(key, r);
+ first = true;
+ } else {
+ r.requests++;
+ }
+ }
- // There is a possible race here. Another thread may try to acquire
- // the same provider at the same time. When this happens, we want to ensure
- // that the first one wins.
- // Note that we cannot hold the lock while acquiring and installing the
- // provider since it might take a long time to run and it could also potentially
- // be re-entrant in the case where the provider is in the same process.
IActivityManager.ContentProviderHolder holder = null;
- try {
- holder = ActivityManagerNative.getDefault().getContentProvider(
- getApplicationThread(), auth, userId, stable);
- } catch (RemoteException ex) {
+ if (first) {
+ // Multiple threads may try to acquire the same provider at the same time.
+ // When this happens, we only let the first one really gets provider.
+ // Other threads just wait for its result.
+ // Note that we cannot hold the lock while acquiring and installing the
+ // provider since it might take a long time to run and it could also potentially
+ // be re-entrant in the case where the provider is in the same process.
+ try {
+ holder = ActivityManagerNative.getDefault().getContentProvider(
+ getApplicationThread(), auth, userId, stable);
+ } catch (RemoteException ex) {
+ }
+ synchronized (r) {
+ r.holder = holder;
+ r.acquiring = false;
+ r.notifyAll();
+ }
+ } else {
+ synchronized (r) {
+ while (r.acquiring) {
+ try {
+ r.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ holder = r.holder;
+ }
+ }
+ synchronized (mAcquiringProviderMap) {
+ if (--r.requests == 0) {
+ mAcquiringProviderMap.remove(key);
+ }
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
@@ -4792,8 +4830,12 @@
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
+ return acquireExistingProvider(c, new ProviderKey(auth, userId), stable);
+ }
+
+ final IContentProvider acquireExistingProvider(
+ Context c, ProviderKey key, boolean stable) {
synchronized (mProviderMap) {
- final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
@@ -4804,7 +4846,7 @@
if (!jBinder.isBinderAlive()) {
// The hosting process of the provider has died; we can't
// use this one.
- Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+ Log.i(TAG, "Acquiring provider " + key.authority + " for user " + key.userId
+ ": existing object's process dead");
handleUnstableProviderDiedLocked(jBinder, true);
return null;
@@ -5126,18 +5168,12 @@
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, updating ref count");
}
- // We need to transfer our new reference to the existing
- // ref count, releasing the old one... but only if
- // release is needed (that is, it is not running in the
- // system process).
+ // The provider has already been installed, so we need
+ // to increase reference count to the existing one, but
+ // only if release is needed (that is, it is not running
+ // in the system process or local to the process).
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
- try {
- ActivityManagerNative.getDefault().removeContentProvider(
- holder.connection, stable);
- } catch (RemoteException e) {
- //do nothing content provider object is dead any way
- }
}
} else {
ProviderClientRecord client = installProviderAuthoritiesLocked(
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6d74905..6ec5457 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -36,6 +36,7 @@
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
import android.content.pm.ManifestDigest;
import android.content.pm.PackageInfo;
@@ -1309,6 +1310,45 @@
}
@Override
+ public void verifyIntentFilter(int id, int verificationCode, List<String> outFailedDomains) {
+ try {
+ mPM.verifyIntentFilter(id, verificationCode, outFailedDomains);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ }
+
+ @Override
+ public int getIntentVerificationStatus(String packageName, int userId) {
+ try {
+ return mPM.getIntentVerificationStatus(packageName, userId);
+ } catch (RemoteException e) {
+ // Should never happen!
+ return PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ }
+ }
+
+ @Override
+ public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+ try {
+ return mPM.updateIntentVerificationStatus(packageName, status, userId);
+ } catch (RemoteException e) {
+ // Should never happen!
+ return false;
+ }
+ }
+
+ @Override
+ public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
+ try {
+ return mPM.getIntentFilterVerifications(packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ return null;
+ }
+ }
+
+ @Override
public void setInstallerPackageName(String targetPackage,
String installerPackageName) {
try {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 59fe490..a0f40f6 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -402,13 +402,7 @@
new CachedServiceFetcher<StorageManager>() {
@Override
public StorageManager createService(ContextImpl ctx) {
- try {
- return new StorageManager(
- ctx.getContentResolver(), ctx.mMainThread.getHandler().getLooper());
- } catch (RemoteException rex) {
- Log.e(TAG, "Failed to create StorageManager", rex);
- return null;
- }
+ return new StorageManager(ctx, ctx.mMainThread.getHandler().getLooper());
}});
registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index cf6619f..cbb0f51 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3165,6 +3165,22 @@
}
/**
+ * Start Quick Contact on the managed profile for the current user, if the policy allows.
+ * @hide
+ */
+ public void startManagedQuickContact(String actualLookupKey, long actualContactId,
+ Intent originalIntent) {
+ if (mService != null) {
+ try {
+ mService.startManagedQuickContact(
+ actualLookupKey, actualContactId, originalIntent);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
* Called by the profile owner of a managed profile so that some intents sent in the managed
* profile can also be resolved in the parent, or vice versa.
* Only activity intents are supported.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 9ca52e5..73b0684 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -189,6 +189,7 @@
void setCrossProfileCallerIdDisabled(in ComponentName who, boolean disabled);
boolean getCrossProfileCallerIdDisabled(in ComponentName who);
boolean getCrossProfileCallerIdDisabledForUser(int userId);
+ void startManagedQuickContact(String lookupKey, long contactId, in Intent originalIntent);
void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent,
in PersistableBundle args);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 030b770..514802e9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1041,6 +1041,18 @@
*/
public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
/**
+ * Activity action: Activate the current SIM card. If SIM cards do not require activation,
+ * sending this intent is a no-op.
+ * <p>Input: No data should be specified. get*Extra may have an optional
+ * {@link #EXTRA_SIM_ACTIVATION_RESPONSE} field containing a PendingIntent through which to
+ * send the activation result.
+ * <p>Output: nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SIM_ACTIVATION_REQUEST =
+ "android.intent.action.SIM_ACTIVATION_REQUEST";
+ /**
* Activity Action: Send a message to someone specified by the data.
* <p>Input: {@link #getData} is URI describing the target.
* <p>Output: nothing.
@@ -1911,6 +1923,19 @@
public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
/**
+ * Broadcast Action: Sent to the system intent filter verifier when an intent filter
+ * needs to be verified. The data contains the filter data hosts to be verified against.
+ * <p class="note">
+ * This is a protected intent that can only be sent by the system.
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
+
+ /**
* Broadcast Action: Resources for a set of packages (which were
* previously unavailable) are currently
* available since the media on which they exist is available.
@@ -3607,6 +3632,15 @@
/** {@hide} */
public static final String EXTRA_REASON = "android.intent.extra.REASON";
+ /**
+ * Optional {@link android.app.PendingIntent} extra used to deliver the result of the SIM
+ * activation request.
+ * TODO: Add information about the structure and response data used with the pending intent.
+ * @hide
+ */
+ public static final String EXTRA_SIM_ACTIVATION_RESPONSE =
+ "android.intent.extra.SIM_ACTIVATION_RESPONSE";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 1240a23..590d791 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -16,10 +16,12 @@
package android.content;
+import android.content.pm.PackageParser;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PatternMatcher;
+import android.text.TextUtils;
import android.util.AndroidException;
import android.util.Log;
import android.util.Printer;
@@ -150,6 +152,7 @@
private static final String CAT_STR = "cat";
private static final String NAME_STR = "name";
private static final String ACTION_STR = "action";
+ private static final String AUTO_VERIFY_STR = "autoVerify";
/**
* The filter {@link #setPriority} value at which system high-priority
@@ -247,6 +250,19 @@
*/
public static final int NO_MATCH_CATEGORY = -4;
+ /**
+ * HTTP scheme.
+ *
+ * @see #addDataScheme(String)
+ */
+ public static final String SCHEME_HTTP = "http";
+ /**
+ * HTTPS scheme.
+ *
+ * @see #addDataScheme(String)
+ */
+ public static final String SCHEME_HTTPS = "https";
+
private int mPriority;
private final ArrayList<String> mActions;
private ArrayList<String> mCategories = null;
@@ -257,6 +273,13 @@
private ArrayList<String> mDataTypes = null;
private boolean mHasPartialTypes = false;
+ private static final int STATE_VERIFY_AUTO = 0x00000001;
+ private static final int STATE_NEED_VERIFY = 0x00000010;
+ private static final int STATE_NEED_VERIFY_CHECKED = 0x00000100;
+ private static final int STATE_VERIFIED = 0x00001000;
+
+ private int mVerifyState;
+
// These functions are the start of more optimized code for managing
// the string sets... not yet implemented.
@@ -326,7 +349,7 @@
public MalformedMimeTypeException(String name) {
super(name);
}
- };
+ }
/**
* Create a new IntentFilter instance with a specified action and MIME
@@ -421,6 +444,7 @@
mDataPaths = new ArrayList<PatternMatcher>(o.mDataPaths);
}
mHasPartialTypes = o.mHasPartialTypes;
+ mVerifyState = o.mVerifyState;
}
/**
@@ -452,6 +476,94 @@
}
/**
+ * Set whether this filter will needs to be automatically verified against its data URIs or not.
+ * The default is false.
+ *
+ * The verification would need to happen only and only if the Intent action is
+ * {@link android.content.Intent#ACTION_VIEW} and the Intent category is
+ * {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent data scheme
+ * is "http" or "https".
+ *
+ * True means that the filter will need to use its data URIs to be verified.
+ *
+ * @param autoVerify The new autoVerify value.
+ *
+ * @see #getAutoVerify()
+ * @see #addAction(String)
+ * @see #getAction(int)
+ * @see #addCategory(String)
+ * @see #getCategory(int)
+ * @see #addDataScheme(String)
+ * @see #getDataScheme(int)
+ *
+ * @hide
+ */
+ public final void setAutoVerify(boolean autoVerify) {
+ mVerifyState &= ~STATE_VERIFY_AUTO;
+ if (autoVerify) mVerifyState |= STATE_VERIFY_AUTO;
+ }
+
+ /**
+ * Return if this filter will needs to be automatically verified again its data URIs or not.
+ *
+ * @return True if the filter will needs to be automatically verified. False otherwise.
+ *
+ * @see #setAutoVerify(boolean)
+ *
+ * @hide
+ */
+ public final boolean getAutoVerify() {
+ return ((mVerifyState & STATE_VERIFY_AUTO) == 1);
+ }
+
+ /**
+ * Return if this filter needs to be automatically verified again its data URIs or not.
+ *
+ * @return True if the filter needs to be automatically verified. False otherwise.
+ *
+ * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
+ * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent
+ * data scheme is "http" or "https".
+ *
+ * @see #setAutoVerify(boolean)
+ *
+ * @hide
+ */
+ public final boolean needsVerification() {
+ return hasAction(Intent.ACTION_VIEW) &&
+ hasCategory(Intent.CATEGORY_BROWSABLE) &&
+ (hasDataScheme(SCHEME_HTTP) || hasDataScheme(SCHEME_HTTPS)) &&
+ getAutoVerify();
+ }
+
+ /**
+ * Return if this filter has been verified
+ *
+ * @return true if the filter has been verified or if autoVerify is false.
+ *
+ * @hide
+ */
+ public final boolean isVerified() {
+ if ((mVerifyState & STATE_NEED_VERIFY_CHECKED) == STATE_NEED_VERIFY_CHECKED) {
+ return ((mVerifyState & STATE_NEED_VERIFY) == STATE_NEED_VERIFY);
+ }
+ return false;
+ }
+
+ /**
+ * Set if this filter has been verified
+ *
+ * @param verified true if this filter has been verified. False otherwise.
+ *
+ * @hide
+ */
+ public void setVerified(boolean verified) {
+ mVerifyState |= STATE_NEED_VERIFY_CHECKED;
+ mVerifyState &= ~STATE_VERIFIED;
+ if (verified) mVerifyState |= STATE_VERIFIED;
+ }
+
+ /**
* Add a new Intent action to match against. If any actions are included
* in the filter, then an Intent's action must be one of those values for
* it to match. If no actions are included, the Intent action is ignored.
@@ -1333,6 +1445,7 @@
* Write the contents of the IntentFilter as an XML stream.
*/
public void writeToXml(XmlSerializer serializer) throws IOException {
+ serializer.attribute(null, AUTO_VERIFY_STR, Boolean.toString(getAutoVerify()));
int N = countActions();
for (int i=0; i<N; i++) {
serializer.startTag(null, ACTION_STR);
@@ -1407,6 +1520,9 @@
public void readFromXml(XmlPullParser parser) throws XmlPullParserException,
IOException {
+ String autoVerify = parser.getAttributeValue(null, AUTO_VERIFY_STR);
+ setAutoVerify(TextUtils.isEmpty(autoVerify) ? false : Boolean.getBoolean(autoVerify));
+
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1548,6 +1664,11 @@
sb.append(", mHasPartialTypes="); sb.append(mHasPartialTypes);
du.println(sb.toString());
}
+ {
+ sb.setLength(0);
+ sb.append(prefix); sb.append("AutoVerify="); sb.append(getAutoVerify());
+ du.println(sb.toString());
+ }
}
public static final Parcelable.Creator<IntentFilter> CREATOR
@@ -1614,6 +1735,7 @@
}
dest.writeInt(mPriority);
dest.writeInt(mHasPartialTypes ? 1 : 0);
+ dest.writeInt(getAutoVerify() ? 1 : 0);
}
/**
@@ -1680,6 +1802,7 @@
}
mPriority = source.readInt();
mHasPartialTypes = source.readInt() > 0;
+ setAutoVerify(source.readInt() > 0);
}
private final boolean findMimeType(String type) {
@@ -1724,4 +1847,27 @@
return false;
}
+
+ /**
+ * @hide
+ */
+ public ArrayList<String> getHostsList() {
+ ArrayList<String> result = new ArrayList<>();
+ Iterator<IntentFilter.AuthorityEntry> it = authoritiesIterator();
+ if (it != null) {
+ while (it.hasNext()) {
+ IntentFilter.AuthorityEntry entry = it.next();
+ result.add(entry.getHost());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ public String[] getHosts() {
+ ArrayList<String> list = getHostsList();
+ return list.toArray(new String[list.size()]);
+ }
}
diff --git a/core/java/android/content/RestrictionEntry.java b/core/java/android/content/RestrictionEntry.java
index 6d79626..342ee38 100644
--- a/core/java/android/content/RestrictionEntry.java
+++ b/core/java/android/content/RestrictionEntry.java
@@ -20,6 +20,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+import java.util.Objects;
+
/**
* Applications can expose restrictions for a restricted user on a
* multiuser device. The administrator can configure these restrictions that will then be
@@ -33,19 +36,19 @@
public class RestrictionEntry implements Parcelable {
/**
- * A type of restriction. Use this type for information that needs to be transferred across
- * but shouldn't be presented to the user in the UI. Stores a single String value.
+ * Hidden restriction type. Use this type for information that needs to be transferred
+ * across but shouldn't be presented to the user in the UI. Stores a single String value.
*/
public static final int TYPE_NULL = 0;
/**
- * A type of restriction. Use this for storing a boolean value, typically presented as
+ * Restriction of type "bool". Use this for storing a boolean value, typically presented as
* a checkbox in the UI.
*/
public static final int TYPE_BOOLEAN = 1;
/**
- * A type of restriction. Use this for storing a string value, typically presented as
+ * Restriction of type "choice". Use this for storing a string value, typically presented as
* a single-select list. Call {@link #setChoiceEntries(String[])} and
* {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
* and the corresponding values, respectively.
@@ -53,7 +56,7 @@
public static final int TYPE_CHOICE = 2;
/**
- * A type of restriction. Use this for storing a string value, typically presented as
+ * Internal restriction type. Use this for storing a string value, typically presented as
* a single-select list. Call {@link #setChoiceEntries(String[])} and
* {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
* and the corresponding values, respectively.
@@ -64,8 +67,8 @@
public static final int TYPE_CHOICE_LEVEL = 3;
/**
- * A type of restriction. Use this for presenting a multi-select list where more than one
- * entry can be selected, such as for choosing specific titles to white-list.
+ * Restriction of type "multi-select". Use this for presenting a multi-select list where more
+ * than one entry can be selected, such as for choosing specific titles to white-list.
* Call {@link #setChoiceEntries(String[])} and
* {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
* and the corresponding values, respectively.
@@ -75,18 +78,30 @@
public static final int TYPE_MULTI_SELECT = 4;
/**
- * A type of restriction. Use this for storing an integer value. The range of values
+ * Restriction of type "integer". Use this for storing an integer value. The range of values
* is from {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}.
*/
public static final int TYPE_INTEGER = 5;
/**
- * A type of restriction. Use this for storing a string value.
+ * Restriction of type "string". Use this for storing a string value.
* @see #setSelectedString
* @see #getSelectedString
*/
public static final int TYPE_STRING = 6;
+ /**
+ * Restriction of type "bundle". Use this for storing {@link android.os.Bundle bundles} of
+ * restrictions
+ */
+ public static final int TYPE_BUNDLE = 7;
+
+ /**
+ * Restriction of type "bundle_array". Use this for storing arrays of
+ * {@link android.os.Bundle bundles} of restrictions
+ */
+ public static final int TYPE_BUNDLE_ARRAY = 8;
+
/** The type of restriction. */
private int mType;
@@ -100,13 +115,13 @@
private String mDescription;
/** The user-visible set of choices used for single-select and multi-select lists. */
- private String [] mChoiceEntries;
+ private String[] mChoiceEntries;
/** The values corresponding to the user-visible choices. The value(s) of this entry will
* one or more of these, returned by {@link #getAllSelectedStrings()} and
* {@link #getSelectedString()}.
*/
- private String [] mChoiceValues;
+ private String[] mChoiceValues;
/* The chosen value, whose content depends on the type of the restriction. */
private String mCurrentValue;
@@ -115,6 +130,12 @@
private String[] mCurrentValues;
/**
+ * List of nested restrictions. Used by {@link #TYPE_BUNDLE bundle} and
+ * {@link #TYPE_BUNDLE_ARRAY bundle_array} restrictions.
+ */
+ private RestrictionEntry[] mRestrictions;
+
+ /**
* Constructor for specifying the type and key, with no initial value;
*
* @param type the restriction type.
@@ -170,6 +191,35 @@
}
/**
+ * Constructor for {@link #TYPE_BUNDLE}/{@link #TYPE_BUNDLE_ARRAY} type.
+ * @param key the unique key for this restriction
+ * @param restrictionEntries array of nested restriction entries. If the entry, being created
+ * represents a {@link #TYPE_BUNDLE_ARRAY bundle-array}, {@code restrictionEntries} array may
+ * only contain elements of type {@link #TYPE_BUNDLE bundle}.
+ * @param isBundleArray true if this restriction represents
+ * {@link #TYPE_BUNDLE_ARRAY bundle-array} type, otherwise the type will be set to
+ * {@link #TYPE_BUNDLE bundle}.
+ */
+ public RestrictionEntry(String key, RestrictionEntry[] restrictionEntries,
+ boolean isBundleArray) {
+ mKey = key;
+ if (isBundleArray) {
+ mType = TYPE_BUNDLE_ARRAY;
+ if (restrictionEntries != null) {
+ for (RestrictionEntry restriction : restrictionEntries) {
+ if (restriction.getType() != TYPE_BUNDLE) {
+ throw new IllegalArgumentException("bundle_array restriction can only have "
+ + "nested restriction entries of type bundle");
+ }
+ }
+ }
+ } else {
+ mType = TYPE_BUNDLE;
+ }
+ setRestrictions(restrictionEntries);
+ }
+
+ /**
* Sets the type for this restriction.
* @param type the type for this restriction.
*/
@@ -283,6 +333,22 @@
}
/**
+ * Returns array of possible restriction entries that this entry may contain.
+ */
+ public RestrictionEntry[] getRestrictions() {
+ return mRestrictions;
+ }
+
+ /**
+ * Sets an array of possible restriction entries, that this entry may contain.
+ * <p>This method is only relevant for types {@link #TYPE_BUNDLE} and
+ * {@link #TYPE_BUNDLE_ARRAY}
+ */
+ public void setRestrictions(RestrictionEntry[] restrictions) {
+ mRestrictions = restrictions;
+ }
+
+ /**
* Returns the list of possible string values set earlier.
* @return the list of possible values.
*/
@@ -362,27 +428,30 @@
this.mTitle = title;
}
- private boolean equalArrays(String[] one, String[] other) {
- if (one.length != other.length) return false;
- for (int i = 0; i < one.length; i++) {
- if (!one[i].equals(other[i])) return false;
- }
- return true;
- }
-
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof RestrictionEntry)) return false;
final RestrictionEntry other = (RestrictionEntry) o;
- // Make sure that either currentValue matches or currentValues matches.
- return mType == other.mType && mKey.equals(other.mKey)
- &&
- ((mCurrentValues == null && other.mCurrentValues == null
- && mCurrentValue != null && mCurrentValue.equals(other.mCurrentValue))
- ||
- (mCurrentValue == null && other.mCurrentValue == null
- && mCurrentValues != null && equalArrays(mCurrentValues, other.mCurrentValues)));
+ if (mType != other.mType || mKey.equals(other.mKey)) {
+ return false;
+ }
+ if (mCurrentValues == null && other.mCurrentValues == null
+ && mRestrictions == null && other.mRestrictions == null
+ && Objects.equals(mCurrentValue, other.mCurrentValue)) {
+ return true;
+ }
+ if (mCurrentValue == null && other.mCurrentValue == null
+ && mRestrictions == null && other.mRestrictions == null
+ && Arrays.equals(mCurrentValues, other.mCurrentValues)) {
+ return true;
+ }
+ if (mCurrentValue == null && other.mCurrentValue == null
+ && mCurrentValue == null && other.mCurrentValue == null
+ && Arrays.equals(mRestrictions, other.mRestrictions)) {
+ return true;
+ }
+ return false;
}
@Override
@@ -397,28 +466,28 @@
result = 31 * result + value.hashCode();
}
}
+ } else if (mRestrictions != null) {
+ result = 31 * result + Arrays.hashCode(mRestrictions);
}
return result;
}
- private String[] readArray(Parcel in) {
- int count = in.readInt();
- String[] values = new String[count];
- for (int i = 0; i < count; i++) {
- values[i] = in.readString();
- }
- return values;
- }
-
public RestrictionEntry(Parcel in) {
mType = in.readInt();
mKey = in.readString();
mTitle = in.readString();
mDescription = in.readString();
- mChoiceEntries = readArray(in);
- mChoiceValues = readArray(in);
+ mChoiceEntries = in.readStringArray();
+ mChoiceValues = in.readStringArray();
mCurrentValue = in.readString();
- mCurrentValues = readArray(in);
+ mCurrentValues = in.readStringArray();
+ Parcelable[] parcelables = in.readParcelableArray(null);
+ if (parcelables != null) {
+ mRestrictions = new RestrictionEntry[parcelables.length];
+ for (int i = 0; i < parcelables.length; i++) {
+ mRestrictions[i] = (RestrictionEntry) parcelables[i];
+ }
+ }
}
@Override
@@ -426,27 +495,17 @@
return 0;
}
- private void writeArray(Parcel dest, String[] values) {
- if (values == null) {
- dest.writeInt(0);
- } else {
- dest.writeInt(values.length);
- for (int i = 0; i < values.length; i++) {
- dest.writeString(values[i]);
- }
- }
- }
-
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeString(mKey);
dest.writeString(mTitle);
dest.writeString(mDescription);
- writeArray(dest, mChoiceEntries);
- writeArray(dest, mChoiceValues);
+ dest.writeStringArray(mChoiceEntries);
+ dest.writeStringArray(mChoiceValues);
dest.writeString(mCurrentValue);
- writeArray(dest, mCurrentValues);
+ dest.writeStringArray(mCurrentValues);
+ dest.writeParcelableArray(mRestrictions, 0);
}
public static final Creator<RestrictionEntry> CREATOR = new Creator<RestrictionEntry>() {
@@ -461,6 +520,16 @@
@Override
public String toString() {
- return "RestrictionsEntry {type=" + mType + ", key=" + mKey + ", value=" + mCurrentValue + "}";
+ return "RestrictionEntry{" +
+ "mType=" + mType +
+ ", mKey='" + mKey + '\'' +
+ ", mTitle='" + mTitle + '\'' +
+ ", mDescription='" + mDescription + '\'' +
+ ", mChoiceEntries=" + Arrays.toString(mChoiceEntries) +
+ ", mChoiceValues=" + Arrays.toString(mChoiceValues) +
+ ", mCurrentValue='" + mCurrentValue + '\'' +
+ ", mCurrentValues=" + Arrays.toString(mCurrentValues) +
+ ", mRestrictions=" + Arrays.toString(mRestrictions) +
+ '}';
}
}
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 21a6a0d..1fac06e 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -32,12 +32,14 @@
import android.util.Xml;
import com.android.internal.R;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -71,12 +73,15 @@
* android:key="string"
* android:title="string resource"
* android:restrictionType=["bool" | "string" | "integer"
- * | "choice" | "multi-select" | "hidden"]
+ * | "choice" | "multi-select" | "hidden"
+ * | "bundle" | "bundle_array"]
* android:description="string resource"
* android:entries="string-array resource"
* android:entryValues="string-array resource"
- * android:defaultValue="reference"
- * />
+ * android:defaultValue="reference" >
+ * <restriction ... />
+ * ...
+ * </restriction>
* <restriction ... />
* ...
* </restrictions>
@@ -97,6 +102,9 @@
* administrator controlling the values, if the title is not sufficient.</li>
* </ul>
* <p>
+ * Only restrictions of type {@code bundle} and {@code bundle_array} can have one or multiple nested
+ * restriction elements.
+ * <p>
* In your manifest's <code>application</code> section, add the meta-data tag to point to
* the restrictions XML file as shown below:
* <pre>
@@ -537,9 +545,7 @@
XmlResourceParser xml =
appInfo.loadXmlMetaData(mContext.getPackageManager(), META_DATA_APP_RESTRICTIONS);
- List<RestrictionEntry> restrictions = loadManifestRestrictions(packageName, xml);
-
- return restrictions;
+ return loadManifestRestrictions(packageName, xml);
}
private List<RestrictionEntry> loadManifestRestrictions(String packageName,
@@ -550,23 +556,16 @@
} catch (NameNotFoundException nnfe) {
return null;
}
- ArrayList<RestrictionEntry> restrictions = new ArrayList<RestrictionEntry>();
+ ArrayList<RestrictionEntry> restrictions = new ArrayList<>();
RestrictionEntry restriction;
try {
int tagType = xml.next();
while (tagType != XmlPullParser.END_DOCUMENT) {
if (tagType == XmlPullParser.START_TAG) {
- if (xml.getName().equals(TAG_RESTRICTION)) {
- AttributeSet attrSet = Xml.asAttributeSet(xml);
- if (attrSet != null) {
- TypedArray a = appContext.obtainStyledAttributes(attrSet,
- com.android.internal.R.styleable.RestrictionEntry);
- restriction = loadRestriction(appContext, a);
- if (restriction != null) {
- restrictions.add(restriction);
- }
- }
+ restriction = loadRestrictionElement(appContext, xml);
+ if (restriction != null) {
+ restrictions.add(restriction);
}
}
tagType = xml.next();
@@ -582,7 +581,21 @@
return restrictions;
}
- private RestrictionEntry loadRestriction(Context appContext, TypedArray a) {
+ private RestrictionEntry loadRestrictionElement(Context appContext, XmlResourceParser xml)
+ throws IOException, XmlPullParserException {
+ if (xml.getName().equals(TAG_RESTRICTION)) {
+ AttributeSet attrSet = Xml.asAttributeSet(xml);
+ if (attrSet != null) {
+ TypedArray a = appContext.obtainStyledAttributes(attrSet,
+ com.android.internal.R.styleable.RestrictionEntry);
+ return loadRestriction(appContext, a, xml);
+ }
+ }
+ return null;
+ }
+
+ private RestrictionEntry loadRestriction(Context appContext, TypedArray a, XmlResourceParser xml)
+ throws IOException, XmlPullParserException {
String key = a.getString(R.styleable.RestrictionEntry_key);
int restrictionType = a.getInt(
R.styleable.RestrictionEntry_restrictionType, -1);
@@ -633,9 +646,90 @@
restriction.setSelectedState(
a.getBoolean(R.styleable.RestrictionEntry_defaultValue, false));
break;
+ case RestrictionEntry.TYPE_BUNDLE:
+ case RestrictionEntry.TYPE_BUNDLE_ARRAY:
+ final int outerDepth = xml.getDepth();
+ List<RestrictionEntry> restrictionEntries = new ArrayList<>();
+ while (XmlUtils.nextElementWithin(xml, outerDepth)) {
+ RestrictionEntry childEntry = loadRestrictionElement(appContext, xml);
+ if (childEntry == null) {
+ Log.w(TAG, "Child entry cannot be loaded for bundle restriction " + key);
+ } else {
+ restrictionEntries.add(childEntry);
+ if (restrictionType == RestrictionEntry.TYPE_BUNDLE_ARRAY
+ && childEntry.getType() != RestrictionEntry.TYPE_BUNDLE) {
+ Log.w(TAG, "bundle_array " + key
+ + " can only contain entries of type bundle");
+ }
+ }
+ }
+ restriction.setRestrictions(restrictionEntries.toArray(new RestrictionEntry[
+ restrictionEntries.size()]));
+ break;
default:
Log.w(TAG, "Unknown restriction type " + restrictionType);
}
return restriction;
}
+
+ /**
+ * Converts a list of restrictions to the corresponding bundle, using the following mapping:
+ * <table>
+ * <tr><th>RestrictionEntry</th><th>Bundle</th></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_BOOLEAN}</td><td>{@link Bundle#putBoolean}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_CHOICE}, {@link RestrictionEntry#TYPE_CHOICE}</td>
+ * <td>{@link Bundle#putStringArray}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_INTEGER}</td><td>{@link Bundle#putInt}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_STRING}</td><td>{@link Bundle#putString}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_BUNDLE}</td><td>{@link Bundle#putBundle}</td></tr>
+ * <tr><td>{@link RestrictionEntry#TYPE_BUNDLE_ARRAY}</td>
+ * <td>{@link Bundle#putParcelableArray}</td></tr>
+ * </table>
+ * @param entries list of restrictions
+ */
+ public static Bundle convertRestrictionsToBundle(List<RestrictionEntry> entries) {
+ final Bundle bundle = new Bundle();
+ for (RestrictionEntry entry : entries) {
+ addRestrictionToBundle(bundle, entry);
+ }
+ return bundle;
+ }
+
+ private static Bundle addRestrictionToBundle(Bundle bundle, RestrictionEntry entry) {
+ switch (entry.getType()) {
+ case RestrictionEntry.TYPE_BOOLEAN:
+ bundle.putBoolean(entry.getKey(), entry.getSelectedState());
+ break;
+ case RestrictionEntry.TYPE_CHOICE:
+ case RestrictionEntry.TYPE_CHOICE_LEVEL:
+ case RestrictionEntry.TYPE_MULTI_SELECT:
+ bundle.putStringArray(entry.getKey(), entry.getAllSelectedStrings());
+ break;
+ case RestrictionEntry.TYPE_INTEGER:
+ bundle.putInt(entry.getKey(), entry.getIntValue());
+ break;
+ case RestrictionEntry.TYPE_STRING:
+ case RestrictionEntry.TYPE_NULL:
+ bundle.putString(entry.getKey(), entry.getSelectedString());
+ break;
+ case RestrictionEntry.TYPE_BUNDLE:
+ RestrictionEntry[] restrictions = entry.getRestrictions();
+ Bundle childBundle = convertRestrictionsToBundle(Arrays.asList(restrictions));
+ bundle.putBundle(entry.getKey(), childBundle);
+ break;
+ case RestrictionEntry.TYPE_BUNDLE_ARRAY:
+ restrictions = entry.getRestrictions();
+ Bundle[] bundleArray = new Bundle[restrictions.length];
+ for (int i = 0; i < restrictions.length; i++) {
+ bundleArray[i] = addRestrictionToBundle(new Bundle(), restrictions[i]);
+ }
+ bundle.putParcelableArray(entry.getKey(), bundleArray);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported restrictionEntry type: " + entry.getType());
+ }
+ return bundle;
+ }
+
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c6d97f1..66b0d1a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -31,6 +31,7 @@
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
+import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.KeySet;
import android.content.pm.PackageInfo;
@@ -436,6 +437,11 @@
void verifyPendingInstall(int id, int verificationCode);
void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
+ void verifyIntentFilter(int id, int verificationCode, in List<String> outFailedDomains);
+ int getIntentVerificationStatus(String packageName, int userId);
+ boolean updateIntentVerificationStatus(String packageName, int status, int userId);
+ List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName);
+
VerifierDeviceIdentity getVerifierDeviceIdentity();
boolean isFirstBoot();
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.aidl b/core/java/android/content/pm/IntentFilterVerificationInfo.aidl
new file mode 100644
index 0000000..00220e5
--- /dev/null
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+parcelable IntentFilterVerificationInfo;
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
new file mode 100644
index 0000000..60cb4a8
--- /dev/null
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -0,0 +1,224 @@
+/*
+ * 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.content.pm;
+
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * The {@link com.android.server.pm.PackageManagerService} maintains some
+ * {@link IntentFilterVerificationInfo}s for each domain / package / class name per user.
+ *
+ * @hide
+ */
+public final class IntentFilterVerificationInfo implements Parcelable {
+ private static final String TAG = IntentFilterVerificationInfo.class.getName();
+
+ private static final String TAG_DOMAIN = "domain";
+ private static final String ATTR_DOMAIN_NAME = "name";
+ private static final String ATTR_PACKAGE_NAME = "packageName";
+ private static final String ATTR_STATUS = "status";
+
+ private String[] mDomains;
+ private String mPackageName;
+ private int mMainStatus;
+
+ public IntentFilterVerificationInfo() {
+ mPackageName = null;
+ mDomains = new String[0];
+ mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ }
+
+ public IntentFilterVerificationInfo(String packageName, String[] domains) {
+ mPackageName = packageName;
+ mDomains = domains;
+ mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ }
+
+ public IntentFilterVerificationInfo(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ readFromXml(parser);
+ }
+
+ public IntentFilterVerificationInfo(Parcel source) {
+ readFromParcel(source);
+ }
+
+ public String[] getDomains() {
+ return mDomains;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public int getStatus() {
+ return mMainStatus;
+ }
+
+ public void setStatus(int s) {
+ if (s >= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED &&
+ s <= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
+ mMainStatus = s;
+ } else {
+ Log.w(TAG, "Trying to set a non supported status: " + s);
+ }
+ }
+
+ public String getDomainsString() {
+ StringBuilder sb = new StringBuilder();
+ for (String str : mDomains) {
+ if (sb.length() > 0) {
+ sb.append(" ");
+ }
+ sb.append(str);
+ }
+ return sb.toString();
+ }
+
+ String getStringFromXml(XmlPullParser parser, String attribute, String defaultValue) {
+ String value = parser.getAttributeValue(null, attribute);
+ if (value == null) {
+ String msg = "Missing element under " + TAG +": " + attribute + " at " +
+ parser.getPositionDescription();
+ Log.w(TAG, msg);
+ return defaultValue;
+ } else {
+ return value;
+ }
+ }
+
+ int getIntFromXml(XmlPullParser parser, String attribute, int defaultValue) {
+ String value = parser.getAttributeValue(null, attribute);
+ if (TextUtils.isEmpty(value)) {
+ String msg = "Missing element under " + TAG +": " + attribute + " at " +
+ parser.getPositionDescription();
+ Log.w(TAG, msg);
+ return defaultValue;
+ } else {
+ return Integer.parseInt(value);
+ }
+ }
+
+ public void readFromXml(XmlPullParser parser) throws XmlPullParserException,
+ IOException {
+ mPackageName = getStringFromXml(parser, ATTR_PACKAGE_NAME, null);
+ if (mPackageName == null) {
+ Log.e(TAG, "Package name cannot be null!");
+ }
+ int status = getIntFromXml(parser, ATTR_STATUS, -1);
+ if (status == -1) {
+ Log.e(TAG, "Unknown status value: " + status);
+ }
+ mMainStatus = status;
+
+ ArrayList<String> list = new ArrayList<>();
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_DOMAIN)) {
+ String name = getStringFromXml(parser, ATTR_DOMAIN_NAME, null);
+ if (!TextUtils.isEmpty(name)) {
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ list.add(name);
+ }
+ } else {
+ Log.w(TAG, "Unknown tag parsing IntentFilter: " + tagName);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ mDomains = list.toArray(new String[list.size()]);
+ }
+
+ public void writeToXml(XmlSerializer serializer) throws IOException {
+ serializer.attribute(null, ATTR_PACKAGE_NAME, mPackageName);
+ serializer.attribute(null, ATTR_STATUS, String.valueOf(mMainStatus));
+ for (String str : mDomains) {
+ serializer.startTag(null, TAG_DOMAIN);
+ serializer.attribute(null, ATTR_DOMAIN_NAME, str);
+ serializer.endTag(null, TAG_DOMAIN);
+ }
+ }
+
+ public String getStatusString() {
+ return getStatusStringFromValue(mMainStatus);
+ }
+
+ public static String getStatusStringFromValue(int val) {
+ switch (val) {
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK : return "ask";
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS : return "always";
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER : return "never";
+ default:
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED : return "undefined";
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private void readFromParcel(Parcel source) {
+ mPackageName = source.readString();
+ mMainStatus = source.readInt();
+ mDomains = source.readStringArray();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mPackageName);
+ dest.writeInt(mMainStatus);
+ dest.writeStringArray(mDomains);
+ }
+
+ public static final Creator<IntentFilterVerificationInfo> CREATOR =
+ new Creator<IntentFilterVerificationInfo>() {
+ public IntentFilterVerificationInfo createFromParcel(Parcel source) {
+ return new IntentFilterVerificationInfo(source);
+ }
+ public IntentFilterVerificationInfo[] newArray(int size) {
+ return new IntentFilterVerificationInfo[size];
+ }
+ };
+
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f0d1da9..46d6ffb3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -969,6 +969,60 @@
public static final int VERIFICATION_REJECT = -1;
/**
+ * Used as the {@code verificationCode} argument for
+ * {@link PackageManager#verifyIntentFilter} to indicate that the calling
+ * IntentFilter Verifier confirms that the IntentFilter is verified.
+ *
+ * @hide
+ */
+ public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1;
+
+ /**
+ * Used as the {@code verificationCode} argument for
+ * {@link PackageManager#verifyIntentFilter} to indicate that the calling
+ * IntentFilter Verifier confirms that the IntentFilter is NOT verified.
+ *
+ * @hide
+ */
+ public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1;
+
+ /**
+ * Internal status code to indicate that an IntentFilter verification result is not specified.
+ *
+ * @hide
+ */
+ public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED = 0;
+
+ /**
+ * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus}
+ * to indicate that the User will always be prompted the Intent Disambiguation Dialog if there
+ * are two or more Intent resolved for the IntentFilter's domain(s).
+ *
+ * @hide
+ */
+ public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK = 1;
+
+ /**
+ * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus}
+ * to indicate that the User will never be prompted the Intent Disambiguation Dialog if there
+ * are two or more resolution of the Intent. The default App for the domain(s) specified in the
+ * IntentFilter will also ALWAYS be used.
+ *
+ * @hide
+ */
+ public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS = 2;
+
+ /**
+ * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus}
+ * to indicate that the User may be prompted the Intent Disambiguation Dialog if there
+ * are two or more Intent resolved. The default App for the domain(s) specified in the
+ * IntentFilter will also NEVER be presented to the User.
+ *
+ * @hide
+ */
+ public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER = 3;
+
+ /**
* Can be used as the {@code millisecondsToDelay} argument for
* {@link PackageManager#extendVerificationTimeout}. This is the
* maximum time {@code PackageManager} waits for the verification
@@ -1680,8 +1734,52 @@
= "android.content.pm.extra.VERIFICATION_VERSION_CODE";
/**
- * The action used to request that the user approve a grant permissions
- * request from the application.
+ * Extra field name for the ID of a intent filter pending verification. Passed to
+ * an intent filter verifier and is used to call back to
+ * {@link PackageManager#verifyIntentFilter(int, int)}
+ *
+ * @hide
+ */
+ public static final String EXTRA_INTENT_FILTER_VERIFICATION_ID
+ = "android.content.pm.extra.INTENT_FILTER_VERIFICATION_ID";
+
+ /**
+ * Extra field name for the scheme used for an intent filter pending verification. Passed to
+ * an intent filter verifier and is used to construct the URI to verify against.
+ *
+ * Usually this is "https"
+ *
+ * @hide
+ */
+ public static final String EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME
+ = "android.content.pm.extra.INTENT_FILTER_VERIFICATION_URI_SCHEME";
+
+ /**
+ * Extra field name for the host names to be used for an intent filter pending verification.
+ * Passed to an intent filter verifier and is used to construct the URI to verify the
+ * intent filter.
+ *
+ * This is a space delimited list of hosts.
+ *
+ * @hide
+ */
+ public static final String EXTRA_INTENT_FILTER_VERIFICATION_HOSTS
+ = "android.content.pm.extra.INTENT_FILTER_VERIFICATION_HOSTS";
+
+ /**
+ * Extra field name for the package name to be used for an intent filter pending verification.
+ * Passed to an intent filter verifier and is used to check the verification responses coming
+ * from the hosts. Each host response will need to include the package name of APK containing
+ * the intent filter.
+ *
+ * @hide
+ */
+ public static final String EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME
+ = "android.content.pm.extra.INTENT_FILTER_VERIFICATION_PACKAGE_NAME";
+
+ /**
+ * The action used to request that the user approve a permission request
+ * from the application.
*
* @hide
*/
@@ -3461,6 +3559,85 @@
int verificationCodeAtTimeout, long millisecondsToDelay);
/**
+ * Allows a package listening to the
+ * {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION intent filter verification
+ * broadcast} to respond to the package manager. The response must include
+ * the {@code verificationCode} which is one of
+ * {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS} or
+ * {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
+ *
+ * @param verificationId pending package identifier as passed via the
+ * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
+ * @param verificationCode either {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS}
+ * or {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
+ * @param outFailedDomains a list of failed domains if the verificationCode is
+ * {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}, otherwise null;
+ * @throws SecurityException if the caller does not have the
+ * INTENT_FILTER_VERIFICATION_AGENT permission.
+ *
+ * @hide
+ */
+ public abstract void verifyIntentFilter(int verificationId, int verificationCode,
+ List<String> outFailedDomains);
+
+ /**
+ * Get the status of a Domain Verification Result for an IntentFilter. This is
+ * related to the {@link android.content.IntentFilter#setAutoVerify(boolean)} and
+ * {@link android.content.IntentFilter#getAutoVerify()}
+ *
+ * This is used by the ResolverActivity to change the status depending on what the User select
+ * in the Disambiguation Dialog and also used by the Settings App for changing the default App
+ * for a domain.
+ *
+ * @param packageName The package name of the Activity associated with the IntentFilter.
+ * @param userId The user id.
+ *
+ * @return The status to set to. This can be
+ * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK} or
+ * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS} or
+ * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER} or
+ * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED}
+ *
+ * @hide
+ */
+ public abstract int getIntentVerificationStatus(String packageName, int userId);
+
+ /**
+ * Allow to change the status of a Intent Verification status for all IntentFilter of an App.
+ * This is related to the {@link android.content.IntentFilter#setAutoVerify(boolean)} and
+ * {@link android.content.IntentFilter#getAutoVerify()}
+ *
+ * This is used by the ResolverActivity to change the status depending on what the User select
+ * in the Disambiguation Dialog and also used by the Settings App for changing the default App
+ * for a domain.
+ *
+ * @param packageName The package name of the Activity associated with the IntentFilter.
+ * @param status The status to set to. This can be
+ * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK} or
+ * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS} or
+ * {@link #INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER}
+ * @param userId The user id.
+ *
+ * @return true if the status has been set. False otherwise.
+ *
+ * @hide
+ */
+ public abstract boolean updateIntentVerificationStatus(String packageName, int status,
+ int userId);
+
+ /**
+ * Get the list of IntentFilterVerificationInfo for a specific package and User.
+ *
+ * @param packageName the package name. When this parameter is set to a non null value,
+ * the results will be filtered by the package name provided.
+ * Otherwise, there will be no filtering and it will return a list
+ * corresponding for all packages for the provided userId.
+ * @return a list of IntentFilterVerificationInfo for a specific package and User.
+ */
+ public abstract List<IntentFilterVerificationInfo> getIntentFilterVerifications(
+ String packageName);
+
+ /**
* Change the installer associated with a given package. There are limitations
* on how the installer package can be changed; in particular:
* <ul>
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 212cf6d..4b81fd4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2750,15 +2750,21 @@
}
}
- addSharedLibrariesForBackwardCompatibility(owner);
+ modifySharedLibrariesForBackwardCompatibility(owner);
return true;
}
- private static void addSharedLibrariesForBackwardCompatibility(Package owner) {
- if (owner.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
- owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, "org.apache.http.legacy");
- }
+ private static void modifySharedLibrariesForBackwardCompatibility(Package owner) {
+ // "org.apache.http.legacy" is now a part of the boot classpath so it doesn't need
+ // to be an explicit dependency.
+ //
+ // A future change will remove this library from the boot classpath, at which point
+ // all apps that target SDK 21 and earlier will have it automatically added to their
+ // dependency lists.
+ owner.usesLibraries = ArrayUtils.remove(owner.usesLibraries, "org.apache.http.legacy");
+ owner.usesOptionalLibraries = ArrayUtils.remove(owner.usesOptionalLibraries,
+ "org.apache.http.legacy");
}
/**
@@ -3149,7 +3155,7 @@
if (parser.getName().equals("intent-filter")) {
ActivityIntentInfo intent = new ActivityIntentInfo(a);
- if (!parseIntent(res, parser, attrs, true, intent, outError)) {
+ if (!parseIntent(res, parser, attrs, true, true, intent, outError)) {
return null;
}
if (intent.countActions() == 0) {
@@ -3161,7 +3167,7 @@
}
} else if (!receiver && parser.getName().equals("preferred")) {
ActivityIntentInfo intent = new ActivityIntentInfo(a);
- if (!parseIntent(res, parser, attrs, false, intent, outError)) {
+ if (!parseIntent(res, parser, attrs, false, false, intent, outError)) {
return null;
}
if (intent.countActions() == 0) {
@@ -3341,7 +3347,7 @@
if (parser.getName().equals("intent-filter")) {
ActivityIntentInfo intent = new ActivityIntentInfo(a);
- if (!parseIntent(res, parser, attrs, true, intent, outError)) {
+ if (!parseIntent(res, parser, attrs, true, true, intent, outError)) {
return null;
}
if (intent.countActions() == 0) {
@@ -3521,7 +3527,7 @@
if (parser.getName().equals("intent-filter")) {
ProviderIntentInfo intent = new ProviderIntentInfo(outInfo);
- if (!parseIntent(res, parser, attrs, true, intent, outError)) {
+ if (!parseIntent(res, parser, attrs, true, false, intent, outError)) {
return false;
}
outInfo.intents.add(intent);
@@ -3780,7 +3786,7 @@
if (parser.getName().equals("intent-filter")) {
ServiceIntentInfo intent = new ServiceIntentInfo(s);
- if (!parseIntent(res, parser, attrs, true, intent, outError)) {
+ if (!parseIntent(res, parser, attrs, true, false, intent, outError)) {
return null;
}
@@ -3981,7 +3987,7 @@
= "http://schemas.android.com/apk/res/android";
private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs,
- boolean allowGlobs, IntentInfo outInfo, String[] outError)
+ boolean allowGlobs, boolean allowAutoVerify, IntentInfo outInfo, String[] outError)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(attrs,
@@ -4006,6 +4012,12 @@
outInfo.banner = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
+ if (allowAutoVerify) {
+ outInfo.setAutoVerify(sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestIntentFilter_autoVerify,
+ false));
+ }
+
sa.recycle();
int outerDepth = parser.getDepth();
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index a9c7be3..92b8055 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -37,10 +37,14 @@
public ArraySet<String> disabledComponents;
public ArraySet<String> enabledComponents;
+ public int domainVerificationStatus;
+
public PackageUserState() {
installed = true;
hidden = false;
enabled = COMPONENT_ENABLED_STATE_DEFAULT;
+ domainVerificationStatus =
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
public PackageUserState(PackageUserState o) {
@@ -51,9 +55,10 @@
hidden = o.hidden;
lastDisableAppCaller = o.lastDisableAppCaller;
disabledComponents = o.disabledComponents != null
- ? new ArraySet<String>(o.disabledComponents) : null;
+ ? new ArraySet<>(o.disabledComponents) : null;
enabledComponents = o.enabledComponents != null
- ? new ArraySet<String>(o.enabledComponents) : null;
+ ? new ArraySet<>(o.enabledComponents) : null;
blockUninstall = o.blockUninstall;
+ domainVerificationStatus = o.domainVerificationStatus;
}
}
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index fe3aec9..7b141f0 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -143,6 +143,11 @@
*/
public boolean system;
+ /**
+ * @hide Does the associated IntentFilter needs verification ?
+ */
+ public boolean filterNeedsVerification;
+
private ComponentInfo getComponentInfo() {
if (activityInfo != null) return activityInfo;
if (serviceInfo != null) return serviceInfo;
@@ -283,6 +288,7 @@
resolvePackageName = orig.resolvePackageName;
system = orig.system;
targetUserId = orig.targetUserId;
+ filterNeedsVerification = orig.filterNeedsVerification;
}
public String toString() {
@@ -344,6 +350,7 @@
dest.writeInt(targetUserId);
dest.writeInt(system ? 1 : 0);
dest.writeInt(noResourceId ? 1 : 0);
+ dest.writeInt(filterNeedsVerification ? 1 : 0);
}
public static final Creator<ResolveInfo> CREATOR
@@ -389,6 +396,7 @@
targetUserId = source.readInt();
system = source.readInt() != 0;
noResourceId = source.readInt() != 0;
+ filterNeedsVerification = source.readInt() != 0;
}
public static class DisplayNameComparator
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index d5dfaf6..9bc2f46 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -75,4 +75,11 @@
out BinderHolder device);
int setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);
+
+ /**
+ * Notify the camera service of a system event. Should only be called from system_server.
+ *
+ * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
+ */
+ oneway void notifySystemEvent(int eventId, int arg0);
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index a0217c2..1503bf5 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -991,7 +991,8 @@
* <ul>
* <li>Processed (but stalling): any non-RAW format with a stallDurations > 0.
* Typically JPEG format (ImageFormat#JPEG).</li>
- * <li>Raw formats: ImageFormat#RAW_SENSOR, ImageFormat#RAW10 and ImageFormat#RAW_OPAQUE.</li>
+ * <li>Raw formats: ImageFormat#RAW_SENSOR, ImageFormat#RAW10, ImageFormat#RAW12,
+ * and ImageFormat#RAW_OPAQUE.</li>
* <li>Processed (but not-stalling): any non-RAW format without a stall duration.
* Typically ImageFormat#YUV_420_888, ImageFormat#NV21, ImageFormat#YV12.</li>
* </ul>
@@ -1023,6 +1024,7 @@
* <ul>
* <li>ImageFormat#RAW_SENSOR</li>
* <li>ImageFormat#RAW10</li>
+ * <li>ImageFormat#RAW12</li>
* <li>Opaque <code>RAW</code></li>
* </ul>
* <p>LEGACY mode devices ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> LEGACY)
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index a94c1da..a336e5c 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -168,7 +168,22 @@
}
/**
- * Sets system audio volume
+ * Sets system audio mode.
+ *
+ * @param enabled set to {@code true} to enable the mode; otherwise {@code false}
+ * @param callback callback to get the result with
+ * @throws {@link IllegalArgumentException} if the {@code callback} is null
+ */
+ public void setSystemAudioMode(boolean enabled, SelectCallback callback) {
+ try {
+ mService.setSystemAudioMode(enabled, getCallbackWrapper(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to set system audio mode:", e);
+ }
+ }
+
+ /**
+ * Sets system audio volume.
*
* @param oldIndex current volume index
* @param newIndex volume index to be set
@@ -183,7 +198,7 @@
}
/**
- * Sets system audio mute status
+ * Sets system audio mute status.
*
* @param mute {@code true} if muted; otherwise, {@code false}
*/
@@ -196,7 +211,7 @@
}
/**
- * Sets record listener
+ * Sets record listener.
*
* @param listener
*/
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a0e2bf8..3abccbc 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -40,6 +40,7 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.net.VpnConfig;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.Protocol;
@@ -2447,6 +2448,38 @@
}
/**
+ * Resets all connectivity manager settings back to factory defaults.
+ * @hide
+ */
+ public void factoryReset() {
+ // Turn airplane mode off
+ setAirplaneMode(false);
+
+ // Untether
+ for (String tether : getTetheredIfaces()) {
+ untether(tether);
+ }
+
+ // Turn VPN off
+ try {
+ VpnConfig vpnConfig = mService.getVpnConfig();
+ if (vpnConfig != null) {
+ if (vpnConfig.legacy) {
+ mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
+ } else {
+ // Prevent this app from initiating VPN connections in the future without
+ // user intervention.
+ mService.setVpnPackageAuthorization(false);
+
+ mService.prepareVpn(vpnConfig.user, VpnConfig.LEGACY_VPN);
+ }
+ }
+ } catch (RemoteException e) {
+ // Well, we tried
+ }
+ }
+
+ /**
* Binds the current process to {@code network}. All Sockets created in the future
* (and not explicitly bound via a bound SocketFactory from
* {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index a8e7757..a7ffee9 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -180,6 +180,33 @@
}
/**
+ * Resets network policy settings back to factory defaults.
+ *
+ * @hide
+ */
+ public void factoryReset(String subscriber) {
+ // Turn mobile data limit off
+ NetworkPolicy[] policies = getNetworkPolicies();
+ NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(subscriber);
+ for (NetworkPolicy policy : policies) {
+ if (policy.template.equals(template)) {
+ policy.limitBytes = NetworkPolicy.LIMIT_DISABLED;
+ policy.inferred = false;
+ policy.clearSnooze();
+ }
+ }
+ setNetworkPolicies(policies);
+
+ // Turn restrict background data off
+ setRestrictBackground(false);
+
+ // Remove app's "restrict background data" flag
+ for (int uid : getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
+ setUidPolicy(uid, NetworkPolicyManager.POLICY_NONE);
+ }
+ }
+
+ /**
* Compute the last cycle boundary for the given {@link NetworkPolicy}. For
* example, if cycle day is 20th, and today is June 15th, it will return May
* 20th. When cycle day doesn't exist in current month, it snaps to the 1st
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 3f18519..ff3de2b 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -51,6 +51,8 @@
public static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
/** @hide */
public static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
+ /** @hide */
+ public static final long TB_IN_BYTES = GB_IN_BYTES * 1024;
/**
* Special UID value used when collecting {@link NetworkStatsHistory} for
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index bf3d9aa..f305b2a 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -366,7 +366,6 @@
public String toSafeString() {
String scheme = getScheme();
String ssp = getSchemeSpecificPart();
- String authority = null;
if (scheme != null) {
if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
|| scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
@@ -385,9 +384,11 @@
}
}
return builder.toString();
- } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
- ssp = null;
- authority = "//" + getAuthority() + "/...";
+ } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")
+ || scheme.equalsIgnoreCase("ftp")) {
+ ssp = "//" + ((getHost() != null) ? getHost() : "")
+ + ((getPort() != -1) ? (":" + getPort()) : "")
+ + "/...";
}
}
// Not a sensitive scheme, but let's still be conservative about
@@ -401,9 +402,6 @@
if (ssp != null) {
builder.append(ssp);
}
- if (authority != null) {
- builder.append(authority);
- }
return builder.toString();
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8b3ecae..508fdee 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -4415,7 +4415,7 @@
if (!checkin) {
pw.println(header);
}
- String[] lineArgs = new String[4];
+ String[] lineArgs = new String[5];
for (int i=0; i<count; i++) {
long duration = steps.getDurationAt(i);
int level = steps.getLevelAt(i);
@@ -4430,7 +4430,7 @@
case Display.STATE_ON: lineArgs[2] = "s+"; break;
case Display.STATE_DOZE: lineArgs[2] = "sd"; break;
case Display.STATE_DOZE_SUSPEND: lineArgs[2] = "sds"; break;
- default: lineArgs[1] = "?"; break;
+ default: lineArgs[2] = "?"; break;
}
} else {
lineArgs[2] = "";
@@ -4441,9 +4441,9 @@
lineArgs[3] = "";
}
if ((modMode&STEP_LEVEL_MODE_DEVICE_IDLE) == 0) {
- lineArgs[3] = (initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0 ? "i+" : "i-";
+ lineArgs[4] = (initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0 ? "i+" : "i-";
} else {
- lineArgs[3] = "";
+ lineArgs[4] = "";
}
dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs);
} else {
@@ -4459,7 +4459,7 @@
case Display.STATE_ON: pw.print("screen-on"); break;
case Display.STATE_DOZE: pw.print("screen-doze"); break;
case Display.STATE_DOZE_SUSPEND: pw.print("screen-doze-suspend"); break;
- default: lineArgs[1] = "screen-?"; break;
+ default: pw.print("screen-?"); break;
}
haveModes = true;
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 975bfc2..2db976e 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -18,16 +18,11 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
-import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
-import android.text.TextUtils;
import android.util.Log;
-import com.google.android.collect.Lists;
-
import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
/**
* Provides access to environment variables.
@@ -36,11 +31,9 @@
private static final String TAG = "Environment";
private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
- private static final String ENV_EMULATED_STORAGE_SOURCE = "EMULATED_STORAGE_SOURCE";
- private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
- private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE";
- private static final String ENV_SECONDARY_STORAGE = "SECONDARY_STORAGE";
private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
+ private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
+ private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
private static final String ENV_OEM_ROOT = "OEM_ROOT";
private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
@@ -57,12 +50,10 @@
public static final String DIRECTORY_ANDROID = DIR_ANDROID;
private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
+ private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
+ private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
- private static final File DIR_MEDIA_STORAGE = getDirectory(ENV_MEDIA_STORAGE, "/data/media");
-
- private static final String CANONCIAL_EMULATED_STORAGE_TARGET = getCanonicalPathOrNull(
- ENV_EMULATED_STORAGE_TARGET);
private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
@@ -81,73 +72,24 @@
/** {@hide} */
public static class UserEnvironment {
- // TODO: generalize further to create package-specific environment
-
- /** External storage dirs, as visible to vold */
- private final File[] mExternalDirsForVold;
- /** External storage dirs, as visible to apps */
- private final File[] mExternalDirsForApp;
- /** Primary emulated storage dir for direct access */
- private final File mEmulatedDirForDirect;
+ private final int mUserId;
public UserEnvironment(int userId) {
- // See storage config details at http://source.android.com/tech/storage/
- String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
- String rawEmulatedSource = System.getenv(ENV_EMULATED_STORAGE_SOURCE);
- String rawEmulatedTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
+ mUserId = userId;
+ }
- String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE);
- if (TextUtils.isEmpty(rawMediaStorage)) {
- rawMediaStorage = "/data/media";
+ public File[] getExternalDirs() {
+ final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId);
+ final File[] dirs = new File[volumes.length];
+ for (int i = 0; i < volumes.length; i++) {
+ dirs[i] = volumes[i].getPathFile();
}
-
- ArrayList<File> externalForVold = Lists.newArrayList();
- ArrayList<File> externalForApp = Lists.newArrayList();
-
- if (!TextUtils.isEmpty(rawEmulatedTarget)) {
- // Device has emulated storage; external storage paths should have
- // userId burned into them.
- final String rawUserId = Integer.toString(userId);
- final File emulatedSourceBase = new File(rawEmulatedSource);
- final File emulatedTargetBase = new File(rawEmulatedTarget);
- final File mediaBase = new File(rawMediaStorage);
-
- // /storage/emulated/0
- externalForVold.add(buildPath(emulatedSourceBase, rawUserId));
- externalForApp.add(buildPath(emulatedTargetBase, rawUserId));
- // /data/media/0
- mEmulatedDirForDirect = buildPath(mediaBase, rawUserId);
-
- } else {
- // Device has physical external storage; use plain paths.
- if (TextUtils.isEmpty(rawExternalStorage)) {
- Log.w(TAG, "EXTERNAL_STORAGE undefined; falling back to default");
- rawExternalStorage = "/storage/sdcard0";
- }
-
- // /storage/sdcard0
- externalForVold.add(new File(rawExternalStorage));
- externalForApp.add(new File(rawExternalStorage));
- // /data/media
- mEmulatedDirForDirect = new File(rawMediaStorage);
- }
-
- // Splice in any secondary storage paths, but only for owner
- final String rawSecondaryStorage = System.getenv(ENV_SECONDARY_STORAGE);
- if (!TextUtils.isEmpty(rawSecondaryStorage) && userId == UserHandle.USER_OWNER) {
- for (String secondaryPath : rawSecondaryStorage.split(":")) {
- externalForVold.add(new File(secondaryPath));
- externalForApp.add(new File(secondaryPath));
- }
- }
-
- mExternalDirsForVold = externalForVold.toArray(new File[externalForVold.size()]);
- mExternalDirsForApp = externalForApp.toArray(new File[externalForApp.size()]);
+ return dirs;
}
@Deprecated
public File getExternalStorageDirectory() {
- return mExternalDirsForApp[0];
+ return getExternalDirs()[0];
}
@Deprecated
@@ -155,60 +97,36 @@
return buildExternalStoragePublicDirs(type)[0];
}
- public File[] getExternalDirsForVold() {
- return mExternalDirsForVold;
- }
-
- public File[] getExternalDirsForApp() {
- return mExternalDirsForApp;
- }
-
- public File getMediaDir() {
- return mEmulatedDirForDirect;
- }
-
public File[] buildExternalStoragePublicDirs(String type) {
- return buildPaths(mExternalDirsForApp, type);
+ return buildPaths(getExternalDirs(), type);
}
public File[] buildExternalStorageAndroidDataDirs() {
- return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA);
+ return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA);
}
public File[] buildExternalStorageAndroidObbDirs() {
- return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB);
+ return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB);
}
public File[] buildExternalStorageAppDataDirs(String packageName) {
- return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName);
- }
-
- public File[] buildExternalStorageAppDataDirsForVold(String packageName) {
- return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_DATA, packageName);
+ return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName);
}
public File[] buildExternalStorageAppMediaDirs(String packageName) {
- return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_MEDIA, packageName);
- }
-
- public File[] buildExternalStorageAppMediaDirsForVold(String packageName) {
- return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_MEDIA, packageName);
+ return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_MEDIA, packageName);
}
public File[] buildExternalStorageAppObbDirs(String packageName) {
- return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_OBB, packageName);
- }
-
- public File[] buildExternalStorageAppObbDirsForVold(String packageName) {
- return buildPaths(mExternalDirsForVold, DIR_ANDROID, DIR_OBB, packageName);
+ return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB, packageName);
}
public File[] buildExternalStorageAppFilesDirs(String packageName) {
- return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
+ return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
}
public File[] buildExternalStorageAppCacheDirs(String packageName) {
- return buildPaths(mExternalDirsForApp, DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);
+ return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);
}
}
@@ -220,6 +138,11 @@
return DIR_ANDROID_ROOT;
}
+ /** {@hide} */
+ public static File getStorageDirectory() {
+ return DIR_ANDROID_STORAGE;
+ }
+
/**
* Return root directory of the "oem" partition holding OEM customizations,
* if any. If present, the partition is mounted read-only.
@@ -270,17 +193,6 @@
}
/**
- * Return directory used for internal media storage, which is protected by
- * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
- *
- * @hide
- */
- public static File getMediaStorageDirectory() {
- throwIfUserRequired();
- return sCurrentUser.getMediaDir();
- }
-
- /**
* Return the system directory for a user. This is for use by system services to store
* files relating to the user. This directory will be automatically deleted when the user
* is removed.
@@ -389,7 +301,7 @@
*/
public static File getExternalStorageDirectory() {
throwIfUserRequired();
- return sCurrentUser.getExternalDirsForApp()[0];
+ return sCurrentUser.getExternalDirs()[0];
}
/** {@hide} */
@@ -402,18 +314,6 @@
return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
}
- /** {@hide} */
- public static File getEmulatedStorageSource(int userId) {
- // /mnt/shell/emulated/0
- return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), String.valueOf(userId));
- }
-
- /** {@hide} */
- public static File getEmulatedStorageObbSource() {
- // /mnt/shell/emulated/obb
- return new File(System.getenv(ENV_EMULATED_STORAGE_SOURCE), DIR_OBB);
- }
-
/**
* Standard directory in which to place any audio files that should be
* in the regular list of music for the user.
@@ -683,6 +583,13 @@
public static final String MEDIA_UNMOUNTABLE = "unmountable";
/**
+ * Storage state if the media is in the process of being ejected.
+ *
+ * @see #getExternalStorageState(File)
+ */
+ public static final String MEDIA_EJECTING = "ejecting";
+
+ /**
* Returns the current state of the primary "external" storage device.
*
* @see #getExternalStorageDirectory()
@@ -693,7 +600,7 @@
* {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
*/
public static String getExternalStorageState() {
- final File externalDir = sCurrentUser.getExternalDirsForApp()[0];
+ final File externalDir = sCurrentUser.getExternalDirs()[0];
return getExternalStorageState(externalDir);
}
@@ -716,17 +623,12 @@
* {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
*/
public static String getExternalStorageState(File path) {
- final StorageVolume volume = getStorageVolume(path);
+ final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
if (volume != null) {
- final IMountService mountService = IMountService.Stub.asInterface(
- ServiceManager.getService("mount"));
- try {
- return mountService.getVolumeState(volume.getPath());
- } catch (RemoteException e) {
- }
+ return volume.getState();
+ } else {
+ return MEDIA_UNKNOWN;
}
-
- return Environment.MEDIA_UNKNOWN;
}
/**
@@ -738,7 +640,7 @@
*/
public static boolean isExternalStorageRemovable() {
if (isStorageDisabled()) return false;
- final File externalDir = sCurrentUser.getExternalDirsForApp()[0];
+ final File externalDir = sCurrentUser.getExternalDirs()[0];
return isExternalStorageRemovable(externalDir);
}
@@ -753,7 +655,7 @@
* device.
*/
public static boolean isExternalStorageRemovable(File path) {
- final StorageVolume volume = getStorageVolume(path);
+ final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
if (volume != null) {
return volume.isRemovable();
} else {
@@ -771,7 +673,7 @@
*/
public static boolean isExternalStorageEmulated() {
if (isStorageDisabled()) return false;
- final File externalDir = sCurrentUser.getExternalDirsForApp()[0];
+ final File externalDir = sCurrentUser.getExternalDirs()[0];
return isExternalStorageEmulated(externalDir);
}
@@ -784,7 +686,7 @@
* device.
*/
public static boolean isExternalStorageEmulated(File path) {
- final StorageVolume volume = getStorageVolume(path);
+ final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
if (volume != null) {
return volume.isEmulated();
} else {
@@ -797,19 +699,6 @@
return path == null ? new File(defaultPath) : new File(path);
}
- private static String getCanonicalPathOrNull(String variableName) {
- String path = System.getenv(variableName);
- if (path == null) {
- return null;
- }
- try {
- return new File(path).getCanonicalPath();
- } catch (IOException e) {
- Log.w(TAG, "Unable to resolve canonical path for " + path);
- return null;
- }
- }
-
/** {@hide} */
public static void setUserRequired(boolean userRequired) {
sUserRequired = userRequired;
@@ -856,28 +745,6 @@
return SystemProperties.getBoolean("config.disable_storage", false);
}
- private static StorageVolume getStorageVolume(File path) {
- try {
- path = path.getCanonicalFile();
- } catch (IOException e) {
- return null;
- }
-
- try {
- final IMountService mountService = IMountService.Stub.asInterface(
- ServiceManager.getService("mount"));
- final StorageVolume[] volumes = mountService.getVolumeList();
- for (StorageVolume volume : volumes) {
- if (FileUtils.contains(volume.getPathFile(), path)) {
- return volume;
- }
- }
- } catch (RemoteException e) {
- }
-
- return null;
- }
-
/**
* If the given path exists on emulated external storage, return the
* translated backing path hosted on internal storage. This bypasses any
@@ -891,26 +758,7 @@
* @hide
*/
public static File maybeTranslateEmulatedPathToInternal(File path) {
- // Fast return if not emulated, or missing variables
- if (!Environment.isExternalStorageEmulated()
- || CANONCIAL_EMULATED_STORAGE_TARGET == null) {
- return path;
- }
-
- try {
- final String rawPath = path.getCanonicalPath();
- if (rawPath.startsWith(CANONCIAL_EMULATED_STORAGE_TARGET)) {
- final File internalPath = new File(DIR_MEDIA_STORAGE,
- rawPath.substring(CANONCIAL_EMULATED_STORAGE_TARGET.length()));
- if (internalPath.exists()) {
- return internalPath;
- }
- }
- } catch (IOException e) {
- Log.w(TAG, "Failed to resolve canonical path for " + path);
- }
-
- // Unable to translate to internal path; use original
+ // TODO: bring back this optimization
return path;
}
}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 0a724a1..b302f95 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -369,6 +369,23 @@
* {@link File#getCanonicalFile()} to avoid symlink or path traversal
* attacks.
*/
+ public static boolean contains(File[] dirs, File file) {
+ for (File dir : dirs) {
+ if (contains(dir, file)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Test if a file lives under the given directory, either as a direct child
+ * or a distant grandchild.
+ * <p>
+ * Both files <em>must</em> have been resolved using
+ * {@link File#getCanonicalFile()} to avoid symlink or path traversal
+ * attacks.
+ */
public static boolean contains(File dir, File file) {
if (file == null) return false;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 0de9c70..355ec8c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -637,10 +637,8 @@
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
- if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
- argsForZygote.add("--mount-external-multiuser");
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) {
- argsForZygote.add("--mount-external-multiuser-all");
+ if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
+ argsForZygote.add("--mount-external-default");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 6209c2a..fef12d1 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -757,12 +757,13 @@
return _result;
}
- public StorageVolume[] getVolumeList() throws RemoteException {
+ public StorageVolume[] getVolumeList(int userId) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
StorageVolume[] _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(userId);
mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArray(StorageVolume.CREATOR);
@@ -1308,7 +1309,8 @@
}
case TRANSACTION_getVolumeList: {
data.enforceInterface(DESCRIPTOR);
- StorageVolume[] result = getVolumeList();
+ int userId = data.readInt();
+ StorageVolume[] result = getVolumeList(userId);
reply.writeNoException();
reply.writeTypedArray(result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
return true;
@@ -1630,7 +1632,7 @@
/**
* Returns list of all mountable volumes.
*/
- public StorageVolume[] getVolumeList() throws RemoteException;
+ public StorageVolume[] getVolumeList(int userId) throws RemoteException;
/**
* Gets the path on the filesystem for the ASEC container itself.
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2785ee8..532bf2c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -18,19 +18,23 @@
import static android.net.TrafficStats.MB_IN_BYTES;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Log;
import android.util.SparseArray;
+import libcore.util.EmptyArray;
+
import com.android.internal.util.Preconditions;
import java.io.File;
@@ -60,6 +64,7 @@
public class StorageManager {
private static final String TAG = "StorageManager";
+ private final Context mContext;
private final ContentResolver mResolver;
/*
@@ -311,8 +316,9 @@
*
* @hide
*/
- public StorageManager(ContentResolver resolver, Looper tgtLooper) throws RemoteException {
- mResolver = resolver;
+ public StorageManager(Context context, Looper tgtLooper) {
+ mContext = context;
+ mResolver = context.getContentResolver();
mTgtLooper = tgtLooper;
mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
if (mMountService == null) {
@@ -548,17 +554,46 @@
return null;
}
+ /** {@hide} */
+ public @Nullable StorageVolume getStorageVolume(File file) {
+ return getStorageVolume(getVolumeList(), file);
+ }
+
+ /** {@hide} */
+ public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
+ return getStorageVolume(getVolumeList(userId), file);
+ }
+
+ /** {@hide} */
+ private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
+ File canonicalFile = null;
+ try {
+ canonicalFile = file.getCanonicalFile();
+ } catch (IOException ignored) {
+ canonicalFile = null;
+ }
+ for (StorageVolume volume : volumes) {
+ if (volume.getPathFile().equals(file)) {
+ return volume;
+ }
+ if (FileUtils.contains(volume.getPathFile(), canonicalFile)) {
+ return volume;
+ }
+ }
+ return null;
+ }
+
/**
* Gets the state of a volume via its mountpoint.
* @hide
*/
- public String getVolumeState(String mountPoint) {
- if (mMountService == null) return Environment.MEDIA_REMOVED;
- try {
- return mMountService.getVolumeState(mountPoint);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get volume state", e);
- return null;
+ @Deprecated
+ public @NonNull String getVolumeState(String mountPoint) {
+ final StorageVolume vol = getStorageVolume(new File(mountPoint));
+ if (vol != null) {
+ return vol.getState();
+ } else {
+ return Environment.MEDIA_UNKNOWN;
}
}
@@ -566,20 +601,22 @@
* Returns list of all mountable volumes.
* @hide
*/
- public StorageVolume[] getVolumeList() {
- if (mMountService == null) return new StorageVolume[0];
+ public @NonNull StorageVolume[] getVolumeList() {
try {
- Parcelable[] list = mMountService.getVolumeList();
- if (list == null) return new StorageVolume[0];
- int length = list.length;
- StorageVolume[] result = new StorageVolume[length];
- for (int i = 0; i < length; i++) {
- result[i] = (StorageVolume)list[i];
- }
- return result;
+ return mMountService.getVolumeList(mContext.getUserId());
} catch (RemoteException e) {
- Log.e(TAG, "Failed to get volume list", e);
- return null;
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** {@hide} */
+ public static @NonNull StorageVolume[] getVolumeList(int userId) {
+ final IMountService mountService = IMountService.Stub.asInterface(
+ ServiceManager.getService("mount"));
+ try {
+ return mountService.getVolumeList(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
}
}
@@ -587,9 +624,9 @@
* Returns list of paths for all mountable volumes.
* @hide
*/
- public String[] getVolumePaths() {
+ @Deprecated
+ public @NonNull String[] getVolumePaths() {
StorageVolume[] volumes = getVolumeList();
- if (volumes == null) return null;
int count = volumes.length;
String[] paths = new String[count];
for (int i = 0; i < count; i++) {
@@ -599,21 +636,21 @@
}
/** {@hide} */
- public StorageVolume getPrimaryVolume() {
+ public @NonNull StorageVolume getPrimaryVolume() {
return getPrimaryVolume(getVolumeList());
}
/** {@hide} */
- public static StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
+ public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
for (StorageVolume volume : volumes) {
if (volume.isPrimary()) {
return volume;
}
}
- Log.w(TAG, "No primary storage defined");
- return null;
+ throw new IllegalStateException("Missing primary storage");
}
+ /** {@hide} */
private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 06565f1..0c391ca 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -17,6 +17,7 @@
package android.os.storage;
import android.content.Context;
+import android.net.TrafficStats;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
@@ -34,52 +35,58 @@
*/
public class StorageVolume implements Parcelable {
- // TODO: switch to more durable token
- private int mStorageId;
+ private final String mId;
+ private final int mStorageId;
private final File mPath;
private final int mDescriptionId;
private final boolean mPrimary;
private final boolean mRemovable;
private final boolean mEmulated;
- private final int mMtpReserveSpace;
+ private final long mMtpReserveSize;
private final boolean mAllowMassStorage;
/** Maximum file size for the storage, or zero for no limit */
private final long mMaxFileSize;
/** When set, indicates exclusive ownership of this volume */
private final UserHandle mOwner;
- private String mUuid;
- private String mUserLabel;
- private String mState;
+ private final String mUuid;
+ private final String mUserLabel;
+ private final String mState;
// StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING,
// ACTION_MEDIA_NOFS, ACTION_MEDIA_MOUNTED, ACTION_MEDIA_SHARED, ACTION_MEDIA_UNSHARED,
// ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
- public StorageVolume(File path, int descriptionId, boolean primary, boolean removable,
- boolean emulated, int mtpReserveSpace, boolean allowMassStorage, long maxFileSize,
- UserHandle owner) {
+ public StorageVolume(String id, int storageId, File path, int descriptionId, boolean primary,
+ boolean removable, boolean emulated, long mtpReserveSize, boolean allowMassStorage,
+ long maxFileSize, UserHandle owner, String uuid, String userLabel, String state) {
+ mId = id;
+ mStorageId = storageId;
mPath = path;
mDescriptionId = descriptionId;
mPrimary = primary;
mRemovable = removable;
mEmulated = emulated;
- mMtpReserveSpace = mtpReserveSpace;
+ mMtpReserveSize = mtpReserveSize;
mAllowMassStorage = allowMassStorage;
mMaxFileSize = maxFileSize;
mOwner = owner;
+ mUuid = uuid;
+ mUserLabel = userLabel;
+ mState = state;
}
private StorageVolume(Parcel in) {
+ mId = in.readString();
mStorageId = in.readInt();
mPath = new File(in.readString());
mDescriptionId = in.readInt();
mPrimary = in.readInt() != 0;
mRemovable = in.readInt() != 0;
mEmulated = in.readInt() != 0;
- mMtpReserveSpace = in.readInt();
+ mMtpReserveSize = in.readLong();
mAllowMassStorage = in.readInt() != 0;
mMaxFileSize = in.readLong();
mOwner = in.readParcelable(null);
@@ -88,10 +95,8 @@
mState = in.readString();
}
- public static StorageVolume fromTemplate(StorageVolume template, File path, UserHandle owner) {
- return new StorageVolume(path, template.mDescriptionId, template.mPrimary,
- template.mRemovable, template.mEmulated, template.mMtpReserveSpace,
- template.mAllowMassStorage, template.mMaxFileSize, owner);
+ public String getId() {
+ return mId;
}
/**
@@ -153,15 +158,6 @@
}
/**
- * Do not call this unless you are MountService
- */
- public void setStorageId(int index) {
- // storage ID is 0x00010001 for primary storage,
- // then 0x00020001, 0x00030001, etc. for secondary storages
- mStorageId = ((index + 1) << 16) + 1;
- }
-
- /**
* Number of megabytes of space to leave unallocated by MTP.
* MTP will subtract this value from the free space it reports back
* to the host via GetStorageInfo, and will not allow new files to
@@ -174,7 +170,7 @@
* @return MTP reserve space
*/
public int getMtpReserveSpace() {
- return mMtpReserveSpace;
+ return (int) (mMtpReserveSize / TrafficStats.MB_IN_BYTES);
}
/**
@@ -199,10 +195,6 @@
return mOwner;
}
- public void setUuid(String uuid) {
- mUuid = uuid;
- }
-
public String getUuid() {
return mUuid;
}
@@ -222,18 +214,10 @@
}
}
- public void setUserLabel(String userLabel) {
- mUserLabel = userLabel;
- }
-
public String getUserLabel() {
return mUserLabel;
}
- public void setState(String state) {
- mState = state;
- }
-
public String getState() {
return mState;
}
@@ -262,13 +246,14 @@
public void dump(IndentingPrintWriter pw) {
pw.println("StorageVolume:");
pw.increaseIndent();
+ pw.printPair("mId", mId);
pw.printPair("mStorageId", mStorageId);
pw.printPair("mPath", mPath);
pw.printPair("mDescriptionId", mDescriptionId);
pw.printPair("mPrimary", mPrimary);
pw.printPair("mRemovable", mRemovable);
pw.printPair("mEmulated", mEmulated);
- pw.printPair("mMtpReserveSpace", mMtpReserveSpace);
+ pw.printPair("mMtpReserveSize", mMtpReserveSize);
pw.printPair("mAllowMassStorage", mAllowMassStorage);
pw.printPair("mMaxFileSize", mMaxFileSize);
pw.printPair("mOwner", mOwner);
@@ -297,13 +282,14 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mId);
parcel.writeInt(mStorageId);
parcel.writeString(mPath.toString());
parcel.writeInt(mDescriptionId);
parcel.writeInt(mPrimary ? 1 : 0);
parcel.writeInt(mRemovable ? 1 : 0);
parcel.writeInt(mEmulated ? 1 : 0);
- parcel.writeInt(mMtpReserveSpace);
+ parcel.writeLong(mMtpReserveSize);
parcel.writeInt(mAllowMassStorage ? 1 : 0);
parcel.writeLong(mMaxFileSize);
parcel.writeParcelable(mOwner, flags);
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 6517f35..7d57233 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -454,7 +454,6 @@
long start, int duration, Long dataUsage, boolean addForAllUsers) {
final ContentResolver resolver = context.getContentResolver();
int numberPresentation = PRESENTATION_ALLOWED;
- boolean isHidden = false;
TelecomManager tm = null;
try {
@@ -469,12 +468,6 @@
if (address != null) {
accountAddress = address.getSchemeSpecificPart();
}
- } else {
- // We could not find the account through telecom. For call log entries that
- // are added with a phone account which is not registered, we automatically
- // mark them as hidden. They are unhidden once the account is registered.
- Log.i(LOG_TAG, "Marking call log entry as hidden.");
- isHidden = true;
}
}
@@ -520,7 +513,6 @@
values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
values.put(PHONE_ACCOUNT_ID, accountId);
values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
- values.put(PHONE_ACCOUNT_HIDDEN, Integer.valueOf(isHidden ? 1 : 0));
values.put(NEW, Integer.valueOf(1));
if (callType == MISSED_TYPE) {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index e4a6f07..bf7f3cb 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -18,6 +18,7 @@
import android.accounts.Account;
import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
@@ -1628,7 +1629,6 @@
*/
public static final String CONTENT_VCARD_TYPE = "text/x-vcard";
-
/**
* Mimimal ID for corp contacts returned from
* {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
@@ -1638,6 +1638,14 @@
public static long ENTERPRISE_CONTACT_ID_BASE = 1000000000; // slightly smaller than 2 ** 30
/**
+ * Prefix for corp contacts returned from
+ * {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI}.
+ *
+ * @hide
+ */
+ public static String ENTERPRISE_CONTACT_LOOKUP_PREFIX = "c-";
+
+ /**
* Return TRUE if a contact ID is from the contacts provider on the enterprise profile.
*
* {@link PhoneLookup#ENTERPRISE_CONTENT_FILTER_URI} may return such a contact.
@@ -5032,9 +5040,17 @@
* is from the corp profile, use
* {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
* </li>
+ * <li>
+ * Corp contacts will get artificial {@link #LOOKUP_KEY}s too.
+ * </li>
* </ul>
* <p>
- * This URI does NOT support selection nor order-by.
+ * A contact lookup URL built by
+ * {@link ContactsContract.Contacts#getLookupUri(long, String)}
+ * with an {@link #_ID} and a {@link #LOOKUP_KEY} returned by this API can be passed to
+ * {@link ContactsContract.QuickContact#showQuickContact} even if a contact is from the
+ * corp profile.
+ * </p>
*
* <pre>
* Uri lookupUri = Uri.withAppendedPath(PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI,
@@ -6025,10 +6041,18 @@
* a contact
* is from the corp profile, use
* {@link ContactsContract.Contacts#isEnterpriseContactId(long)}.
- * </li>
- * </ul>
- * <p>
- * This URI does NOT support selection nor order-by.
+ * </li>
+ * <li>
+ * Corp contacts will get artificial {@link #LOOKUP_KEY}s too.
+ * </li>
+ * </ul>
+ * <p>
+ * A contact lookup URL built by
+ * {@link ContactsContract.Contacts#getLookupUri(long, String)}
+ * with an {@link #_ID} and a {@link #LOOKUP_KEY} returned by this API can be passed to
+ * {@link ContactsContract.QuickContact#showQuickContact} even if a contact is from the
+ * corp profile.
+ * </p>
*
* <pre>
* Uri lookupUri = Uri.withAppendedPath(Email.ENTERPRISE_CONTENT_LOOKUP_URI,
@@ -8182,6 +8206,9 @@
*/
public static final int MODE_LARGE = 3;
+ /** @hide */
+ public static final int MODE_DEFAULT = MODE_LARGE;
+
/**
* Constructs the QuickContacts intent with a view's rect.
* @hide
@@ -8224,6 +8251,7 @@
// Launch pivot dialog through intent for now
final Intent intent = new Intent(ACTION_QUICK_CONTACT).addFlags(intentFlags);
+ // NOTE: This logic and rebuildManagedQuickContactsIntent() must be in sync.
intent.setData(lookupUri);
intent.setSourceBounds(target);
intent.putExtra(EXTRA_MODE, mode);
@@ -8232,6 +8260,30 @@
}
/**
+ * Constructs a QuickContacts intent based on an incoming intent for DevicePolicyManager
+ * to strip off anything not necessary.
+ *
+ * @hide
+ */
+ public static Intent rebuildManagedQuickContactsIntent(String lookupKey, long contactId,
+ Intent originalIntent) {
+ final Intent intent = new Intent(ACTION_QUICK_CONTACT);
+ // Rebuild the URI from a lookup key and a contact ID.
+ intent.setData(Contacts.getLookupUri(contactId, lookupKey));
+
+ // Copy flags and always set NEW_TASK because it won't have a parent activity.
+ intent.setFlags(originalIntent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // Copy extras.
+ intent.setSourceBounds(originalIntent.getSourceBounds());
+ intent.putExtra(EXTRA_MODE, originalIntent.getIntExtra(EXTRA_MODE, MODE_DEFAULT));
+ intent.putExtra(EXTRA_EXCLUDE_MIMES,
+ originalIntent.getStringArrayExtra(EXTRA_EXCLUDE_MIMES));
+ return intent;
+ }
+
+
+ /**
* Trigger a dialog that lists the various methods of interacting with
* the requested {@link Contacts} entry. This may be based on available
* {@link ContactsContract.Data} rows under that contact, and may also
@@ -8259,7 +8311,7 @@
// Trigger with obtained rectangle
Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode,
excludeMimes);
- startActivityWithErrorToast(context, intent);
+ ContactsInternal.startQuickContactWithErrorToast(context, intent);
}
/**
@@ -8292,7 +8344,7 @@
String[] excludeMimes) {
Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode,
excludeMimes);
- startActivityWithErrorToast(context, intent);
+ ContactsInternal.startQuickContactWithErrorToast(context, intent);
}
/**
@@ -8325,10 +8377,10 @@
// Use MODE_LARGE instead of accepting mode as a parameter. The different mode
// values defined in ContactsContract only affect very old implementations
// of QuickContacts.
- Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE,
+ Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT,
excludeMimes);
intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
- startActivityWithErrorToast(context, intent);
+ ContactsInternal.startQuickContactWithErrorToast(context, intent);
}
/**
@@ -8363,19 +8415,10 @@
// Use MODE_LARGE instead of accepting mode as a parameter. The different mode
// values defined in ContactsContract only affect very old implementations
// of QuickContacts.
- Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE,
+ Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_DEFAULT,
excludeMimes);
intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
- startActivityWithErrorToast(context, intent);
- }
-
- private static void startActivityWithErrorToast(Context context, Intent intent) {
- try {
- context.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(context, com.android.internal.R.string.quick_contacts_not_available,
- Toast.LENGTH_SHORT).show();
- }
+ ContactsInternal.startQuickContactWithErrorToast(context, intent);
}
}
diff --git a/core/java/android/provider/ContactsInternal.java b/core/java/android/provider/ContactsInternal.java
new file mode 100644
index 0000000..059a603
--- /dev/null
+++ b/core/java/android/provider/ContactsInternal.java
@@ -0,0 +1,112 @@
+/*
+ * 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.provider;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ActivityNotFoundException;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.Intent;
+import android.content.UriMatcher;
+import android.net.Uri;
+import android.os.Process;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+import java.util.List;
+
+/**
+ * Contacts related internal methods.
+ *
+ * @hide
+ */
+public class ContactsInternal {
+ private ContactsInternal() {
+ }
+
+ /** URI matcher used to parse contact URIs. */
+ private static final UriMatcher sContactsUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+ private static final int CONTACTS_URI_LOOKUP_ID = 1000;
+
+ static {
+ // Contacts URI matching table
+ final UriMatcher matcher = sContactsUriMatcher;
+ matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_URI_LOOKUP_ID);
+ }
+
+ /**
+ * Called by {@link ContactsContract} to star Quick Contact, possibly on the managed profile.
+ */
+ public static void startQuickContactWithErrorToast(Context context, Intent intent) {
+ final Uri uri = intent.getData();
+
+ final int match = sContactsUriMatcher.match(uri);
+ switch (match) {
+ case CONTACTS_URI_LOOKUP_ID: {
+ if (maybeStartManagedQuickContact(context, intent)) {
+ return; // Request handled by DPM. Just return here.
+ }
+ break;
+ }
+ }
+ // Launch on the current profile.
+ startQuickContactWithErrorToastForUser(context, intent, Process.myUserHandle());
+ }
+
+ public static void startQuickContactWithErrorToastForUser(Context context, Intent intent,
+ UserHandle user) {
+ try {
+ context.startActivityAsUser(intent, user);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(context, com.android.internal.R.string.quick_contacts_not_available,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ /**
+ * If the URI in {@code intent} is of a corp contact, launch quick contact on the managed
+ * profile.
+ *
+ * @return the URI in {@code intent} is of a corp contact thus launched on the managed profile.
+ */
+ private static boolean maybeStartManagedQuickContact(Context context, Intent originalIntent) {
+ final Uri uri = originalIntent.getData();
+
+ // Decompose into an ID and a lookup key.
+ final List<String> pathSegments = uri.getPathSegments();
+ final long contactId = ContentUris.parseId(uri);
+ final String lookupKey = pathSegments.get(2);
+
+ // See if it has a corp lookupkey.
+ if (TextUtils.isEmpty(lookupKey)
+ || !lookupKey.startsWith(
+ ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX)) {
+ return false; // It's not a corp lookup key.
+ }
+
+ // Launch Quick Contact on the managed profile, if the policy allows.
+ final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+ final String actualLookupKey = lookupKey.substring(
+ ContactsContract.Contacts.ENTERPRISE_CONTACT_LOOKUP_PREFIX.length());
+ final long actualContactId =
+ (contactId - ContactsContract.Contacts.ENTERPRISE_CONTACT_ID_BASE);
+
+ dpm.startManagedQuickContact(actualLookupKey, actualContactId, originalIntent);
+ return true;
+ }
+}
diff --git a/core/java/android/provider/SearchIndexableData.java b/core/java/android/provider/SearchIndexableData.java
index 7b9d1ea..5e0a76d 100644
--- a/core/java/android/provider/SearchIndexableData.java
+++ b/core/java/android/provider/SearchIndexableData.java
@@ -16,6 +16,7 @@
package android.provider;
+import android.annotation.SystemApi;
import android.content.Context;
import java.util.Locale;
@@ -27,6 +28,7 @@
*
* @hide
*/
+@SystemApi
public abstract class SearchIndexableData {
/**
diff --git a/core/java/android/provider/SearchIndexableResource.java b/core/java/android/provider/SearchIndexableResource.java
index c807df2..1eb1734 100644
--- a/core/java/android/provider/SearchIndexableResource.java
+++ b/core/java/android/provider/SearchIndexableResource.java
@@ -16,6 +16,7 @@
package android.provider;
+import android.annotation.SystemApi;
import android.content.Context;
/**
@@ -31,6 +32,7 @@
*
* @hide
*/
+@SystemApi
public class SearchIndexableResource extends SearchIndexableData {
/**
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index 1b5f72a..93ac7f6 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -16,6 +16,7 @@
package android.provider;
+import android.annotation.SystemApi;
import android.content.ContentResolver;
/**
@@ -23,6 +24,7 @@
*
* @hide
*/
+@SystemApi
public class SearchIndexablesContract {
/**
@@ -234,7 +236,7 @@
/**
* The base columns.
*/
- private static class BaseColumns {
+ public static class BaseColumns {
private BaseColumns() {
}
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 9c8f6d0..3120e54 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -16,6 +16,7 @@
package android.provider;
+import android.annotation.SystemApi;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
@@ -61,6 +62,7 @@
*
* @hide
*/
+@SystemApi
public abstract class SearchIndexablesProvider extends ContentProvider {
private static final String TAG = "IndexablesProvider";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9f3e07c..f79ef35 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6097,7 +6097,7 @@
public static final String PACKAGE_VERIFIER_SETTING_VISIBLE = "verifier_setting_visible";
/**
- * Run package verificaiton on apps installed through ADB/ADT/USB
+ * Run package verification on apps installed through ADB/ADT/USB
* 1 = perform package verification on ADB installs (default)
* 0 = bypass package verification on ADB installs
* @hide
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index 14b5748..579cdbe 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -73,4 +73,6 @@
OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature);
int abort(IBinder handle);
+ boolean isOperationAuthorized(IBinder token);
+ int addAuthToken(in byte[] authToken);
}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index c2ebbc6..e94a312 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -181,7 +181,7 @@
public static final int KM_ERROR_UNSUPPORTED_KEY_SIZE = -6;
public static final int KM_ERROR_UNSUPPORTED_BLOCK_MODE = -7;
public static final int KM_ERROR_INCOMPATIBLE_BLOCK_MODE = -8;
- public static final int KM_ERROR_UNSUPPORTED_TAG_LENGTH = -9;
+ public static final int KM_ERROR_UNSUPPORTED_MAC_LENGTH = -9;
public static final int KM_ERROR_UNSUPPORTED_PADDING_MODE = -10;
public static final int KM_ERROR_INCOMPATIBLE_PADDING_MODE = -11;
public static final int KM_ERROR_UNSUPPORTED_DIGEST = -12;
@@ -237,8 +237,8 @@
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_KEY_SIZE, "Unsupported key size");
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_BLOCK_MODE, "Unsupported block mode");
sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, "Incompatible block mode");
- sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_TAG_LENGTH,
- "Unsupported authentication tag length");
+ sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_MAC_LENGTH,
+ "Unsupported MAC or authentication tag length");
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_PADDING_MODE, "Unsupported padding mode");
sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_PADDING_MODE, "Incompatible padding mode");
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_DIGEST, "Unsupported digest");
@@ -261,6 +261,7 @@
sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_TAG, "Unsupported tag");
sErrorCodeToString.put(KM_ERROR_INVALID_TAG, "Invalid tag");
sErrorCodeToString.put(KM_ERROR_MEMORY_ALLOCATION_FAILED, "Memory allocation failed");
+ sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_EC_FIELD, "Unsupported EC field");
sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
}
diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java
index 4fc9d24..9b46ad3 100644
--- a/core/java/android/security/keymaster/OperationResult.java
+++ b/core/java/android/security/keymaster/OperationResult.java
@@ -28,6 +28,7 @@
public class OperationResult implements Parcelable {
public final int resultCode;
public final IBinder token;
+ public final long operationHandle;
public final int inputConsumed;
public final byte[] output;
@@ -45,6 +46,7 @@
protected OperationResult(Parcel in) {
resultCode = in.readInt();
token = in.readStrongBinder();
+ operationHandle = in.readLong();
inputConsumed = in.readInt();
output = in.createByteArray();
}
@@ -58,6 +60,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(resultCode);
out.writeStrongBinder(token);
+ out.writeLong(operationHandle);
out.writeInt(inputConsumed);
out.writeByteArray(output);
}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 1bdaef0..239b386 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -79,7 +79,8 @@
boolean includepad,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
- spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth);
+ spacingmult, spacingadd, includepad, StaticLayout.BREAK_STRATEGY_SIMPLE,
+ ellipsize, ellipsizedWidth);
}
/**
@@ -95,7 +96,7 @@
TextPaint paint,
int width, Alignment align, TextDirectionHeuristic textDir,
float spacingmult, float spacingadd,
- boolean includepad,
+ boolean includepad, int breakStrategy,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
super((ellipsize == null)
? display
@@ -120,6 +121,7 @@
mObjects = new PackedObjectVector<Directions>(1);
mIncludePad = includepad;
+ mBreakStrategy = breakStrategy;
/*
* This is annoying, but we can't refer to the layout until
@@ -279,10 +281,9 @@
sBuilder = null;
}
- // TODO: make sure reflowed is properly initialized
if (reflowed == null) {
reflowed = new StaticLayout(null);
- b = StaticLayout.Builder.obtain();
+ b = StaticLayout.Builder.obtain(text, where, where + after, getWidth());
}
b.setText(text, where, where + after)
@@ -292,7 +293,8 @@
.setSpacingMult(getSpacingMultiplier())
.setSpacingAdd(getSpacingAdd())
.setEllipsizedWidth(mEllipsizedWidth)
- .setEllipsize(mEllipsizeAt);
+ .setEllipsize(mEllipsizeAt)
+ .setBreakStrategy(mBreakStrategy);
reflowed.generate(b, false, true);
int n = reflowed.getLineCount();
@@ -356,6 +358,8 @@
ints[DESCENT] = desc;
objects[0] = reflowed.getLineDirections(i);
+ ints[HYPHEN] = reflowed.getHyphen(i);
+
if (mEllipsize) {
ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i);
@@ -631,6 +635,14 @@
return mBottomPadding;
}
+ /**
+ * @hide
+ */
+ @Override
+ public int getHyphen(int line) {
+ return mInts.getValue(line, HYPHEN);
+ }
+
@Override
public int getEllipsizedWidth() {
return mEllipsizedWidth;
@@ -707,6 +719,7 @@
private boolean mEllipsize;
private int mEllipsizedWidth;
private TextUtils.TruncateAt mEllipsizeAt;
+ private int mBreakStrategy;
private PackedIntVector mInts;
private PackedObjectVector<Directions> mObjects;
@@ -739,11 +752,12 @@
private static final int TAB = START;
private static final int TOP = 1;
private static final int DESCENT = 2;
- private static final int COLUMNS_NORMAL = 3;
+ private static final int HYPHEN = 3;
+ private static final int COLUMNS_NORMAL = 4;
- private static final int ELLIPSIS_START = 3;
- private static final int ELLIPSIS_COUNT = 4;
- private static final int COLUMNS_ELLIPSIZE = 5;
+ private static final int ELLIPSIS_START = 4;
+ private static final int ELLIPSIS_COUNT = 5;
+ private static final int COLUMNS_ELLIPSIZE = 6;
private static final int START_MASK = 0x1FFFFFFF;
private static final int DIR_SHIFT = 30;
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
new file mode 100644
index 0000000..f4dff9b
--- /dev/null
+++ b/core/java/android/text/Hyphenator.java
@@ -0,0 +1,76 @@
+/*
+ * 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.text;
+
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.HashMap;
+import java.util.Locale;
+
+/**
+ * Hyphenator is a wrapper class for a native implementation of automatic hyphenation,
+ * in essence finding valid hyphenation opportunities in a word.
+ *
+ * @hide
+ */
+/* package */ class Hyphenator {
+ // This class has deliberately simple lifetime management (no finalizer) because in
+ // the common case a process will use a very small number of locales.
+
+ private static String TAG = "Hyphenator";
+
+ static HashMap<Locale, Hyphenator> sMap = new HashMap<Locale, Hyphenator>();
+
+ private long mNativePtr;
+
+ private Hyphenator(long nativePtr) {
+ mNativePtr = nativePtr;
+ }
+
+ public static long get(Locale locale) {
+ synchronized (sMap) {
+ Hyphenator result = sMap.get(locale);
+ if (result == null) {
+ result = loadHyphenator(locale);
+ sMap.put(locale, result);
+ }
+ return result == null ? 0 : result.mNativePtr;
+ }
+ }
+
+ private static Hyphenator loadHyphenator(Locale locale) {
+ // TODO: find pattern dictionary (from system location) that best matches locale
+ if (Locale.US.equals(locale)) {
+ File f = new File("/data/local/tmp/hyph-en-us.pat.txt");
+ try {
+ RandomAccessFile rf = new RandomAccessFile(f, "r");
+ byte[] buf = new byte[(int)rf.length()];
+ rf.read(buf);
+ rf.close();
+ String patternData = new String(buf);
+ long nativePtr = StaticLayout.nLoadHyphenator(patternData);
+ return new Hyphenator(nativePtr);
+ } catch (IOException e) {
+ Log.e(TAG, "error loading hyphenation " + f);
+ }
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 928bf16..16ae5e2 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,6 +16,7 @@
package android.text;
+import android.annotation.IntDef;
import android.emoji.EmojiFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -33,6 +34,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
/**
@@ -43,6 +46,31 @@
* For text that will not change, use a {@link StaticLayout}.
*/
public abstract class Layout {
+ /** @hide */
+ @IntDef({BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BreakStrategy {}
+
+ /**
+ * Value for break strategy indicating simple line breaking. Automatic hyphens are not added
+ * (though soft hyphens are respected), and modifying text generally doesn't affect the layout
+ * before it (which yields a more consistent user experience when editing), but layout may not
+ * be the highest quality.
+ */
+ public static final int BREAK_STRATEGY_SIMPLE = 0;
+
+ /**
+ * Value for break strategy indicating high quality line breaking, including automatic
+ * hyphenation and doing whole-paragraph optimization of line breaks.
+ */
+ public static final int BREAK_STRATEGY_HIGH_QUALITY = 1;
+
+ /**
+ * Value for break strategy indicating balanced line breaking. The breaks are chosen to
+ * make all lines as close to the same length as possible, including automatic hyphenation.
+ */
+ public static final int BREAK_STRATEGY_BALANCED = 2;
+
private static final ParagraphStyle[] NO_PARA_SPANS =
ArrayUtils.emptyArray(ParagraphStyle.class);
@@ -225,17 +253,17 @@
// Draw the lines, one at a time.
// The baseline is the top of the following line minus the current line's descent.
- for (int i = firstLine; i <= lastLine; i++) {
+ for (int lineNum = firstLine; lineNum <= lastLine; lineNum++) {
int start = previousLineEnd;
- previousLineEnd = getLineStart(i + 1);
- int end = getLineVisibleEnd(i, start, previousLineEnd);
+ previousLineEnd = getLineStart(lineNum + 1);
+ int end = getLineVisibleEnd(lineNum, start, previousLineEnd);
int ltop = previousLineBottom;
- int lbottom = getLineTop(i+1);
+ int lbottom = getLineTop(lineNum + 1);
previousLineBottom = lbottom;
- int lbaseline = lbottom - getLineDescent(i);
+ int lbaseline = lbottom - getLineDescent(lineNum);
- int dir = getParagraphDirection(i);
+ int dir = getParagraphDirection(lineNum);
int left = 0;
int right = mWidth;
@@ -254,7 +282,7 @@
// just collect the ones present at the start of the paragraph.
// If spanEnd is before the end of the paragraph, that's not
// our problem.
- if (start >= spanEnd && (i == firstLine || isFirstParaLine)) {
+ if (start >= spanEnd && (lineNum == firstLine || isFirstParaLine)) {
spanEnd = sp.nextSpanTransition(start, textLength,
ParagraphStyle.class);
spans = getParagraphSpans(sp, start, spanEnd, ParagraphStyle.class);
@@ -280,7 +308,7 @@
int startLine = getLineForOffset(sp.getSpanStart(spans[n]));
// if there is more than one LeadingMarginSpan2, use
// the count that is greatest
- if (i < startLine + count) {
+ if (lineNum < startLine + count) {
useFirstLineMargin = true;
break;
}
@@ -304,7 +332,7 @@
}
}
- boolean hasTabOrEmoji = getLineContainsTab(i);
+ boolean hasTabOrEmoji = getLineContainsTab(lineNum);
// Can't tell if we have tabs for sure, currently
if (hasTabOrEmoji && !tabStopsIsInitialized) {
if (tabStops == null) {
@@ -333,7 +361,7 @@
x = right;
}
} else {
- int max = (int)getLineExtent(i, tabStops, false);
+ int max = (int)getLineExtent(lineNum, tabStops, false);
if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_LEFT_TO_RIGHT) {
x = right - max;
@@ -346,7 +374,8 @@
}
}
- Directions directions = getLineDirections(i);
+ paint.setHyphenEdit(getHyphen(lineNum));
+ Directions directions = getLineDirections(lineNum);
if (directions == DIRS_ALL_LEFT_TO_RIGHT && !mSpannedText && !hasTabOrEmoji) {
// XXX: assumes there's nothing additional to be done
canvas.drawText(buf, start, end, x, lbaseline, paint);
@@ -677,6 +706,15 @@
*/
public abstract int getBottomPadding();
+ /**
+ * Returns the hyphen edit for a line.
+ *
+ * @hide
+ */
+ public int getHyphen(int line) {
+ return 0;
+ }
+
/**
* Returns true if the character at offset and the preceding character
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index b47418f..2bcb352 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -23,6 +23,7 @@
import android.text.style.MetricAffectingSpan;
import android.text.style.TabStopSpan;
import android.util.Log;
+import android.util.Pools.SynchronizedPool;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
@@ -56,28 +57,23 @@
mNativePtr = nNewBuilder();
}
- static Builder obtain() {
- Builder b = null;
- synchronized (sLock) {
- for (int i = 0; i < sCached.length; i++) {
- if (sCached[i] != null) {
- b = sCached[i];
- sCached[i] = null;
- break;
- }
- }
- }
+ public static Builder obtain(CharSequence source, int start, int end, int width) {
+ Builder b = sPool.acquire();
if (b == null) {
b = new Builder();
}
// set default initial values
- b.mWidth = 0;
+ b.mText = source;
+ b.mStart = start;
+ b.mEnd = end;
+ b.mWidth = width;
+ b.mAlignment = Alignment.ALIGN_NORMAL;
b.mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
b.mSpacingMult = 1.0f;
b.mSpacingAdd = 0.0f;
b.mIncludePad = true;
- b.mEllipsizedWidth = 0;
+ b.mEllipsizedWidth = width;
b.mEllipsize = null;
b.mMaxLines = Integer.MAX_VALUE;
@@ -85,18 +81,11 @@
return b;
}
- static void recycle(Builder b) {
+ private static void recycle(Builder b) {
b.mPaint = null;
b.mText = null;
MeasuredText.recycle(b.mMeasuredText);
- synchronized (sLock) {
- for (int i = 0; i < sCached.length; i++) {
- if (sCached[i] == null) {
- sCached[i] = b;
- break;
- }
- }
- }
+ sPool.release(b);
}
// release any expensive state
@@ -129,6 +118,11 @@
return this;
}
+ public Builder setAlignment(Alignment alignment) {
+ mAlignment = alignment;
+ return this;
+ }
+
public Builder setTextDir(TextDirectionHeuristic textDir) {
mTextDir = textDir;
return this;
@@ -166,11 +160,17 @@
return this;
}
+ public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
+ mBreakStrategy = breakStrategy;
+ return this;
+ }
+
/**
* Measurement and break iteration is done in native code. The protocol for using
* the native code is as follows.
*
- * For each paragraph, do a nSetText of the paragraph text. Also do nSetLineWidth.
+ * For each paragraph, do a nSetupParagraph, which sets paragraph text, line width, tab
+ * stops, break strategy (and possibly other parameters in the future).
*
* Then, for each run within the paragraph:
* - setLocale (this must be done at least for the first run, optional afterwards)
@@ -187,7 +187,7 @@
private void setLocale(Locale locale) {
if (!locale.equals(mLocale)) {
- nSetLocale(mNativePtr, locale.toLanguageTag());
+ nSetLocale(mNativePtr, locale.toLanguageTag(), Hyphenator.get(locale));
mLocale = locale;
}
}
@@ -206,10 +206,8 @@
}
public StaticLayout build() {
- // TODO: can optimize based on whether ellipsis is needed
- StaticLayout result = new StaticLayout(mText);
- result.generate(this, this.mIncludePad, this.mIncludePad);
- recycle(this);
+ StaticLayout result = new StaticLayout(this);
+ Builder.recycle(this);
return result;
}
@@ -229,6 +227,7 @@
int mEnd;
TextPaint mPaint;
int mWidth;
+ Alignment mAlignment;
TextDirectionHeuristic mTextDir;
float mSpacingMult;
float mSpacingAdd;
@@ -236,6 +235,7 @@
int mEllipsizedWidth;
TextUtils.TruncateAt mEllipsize;
int mMaxLines;
+ int mBreakStrategy;
Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
@@ -244,8 +244,7 @@
Locale mLocale;
- private static final Object sLock = new Object();
- private static final Builder[] sCached = new Builder[3];
+ private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3);
}
public StaticLayout(CharSequence source, TextPaint paint,
@@ -315,10 +314,9 @@
: new Ellipsizer(source),
paint, outerwidth, align, textDir, spacingmult, spacingadd);
- Builder b = Builder.obtain();
- b.setText(source, bufstart, bufend)
+ Builder b = Builder.obtain(source, bufstart, bufend, outerwidth)
.setPaint(paint)
- .setWidth(outerwidth)
+ .setAlignment(align)
.setTextDir(textDir)
.setSpacingMult(spacingmult)
.setSpacingAdd(spacingadd)
@@ -365,6 +363,35 @@
mLines = new int[mLineDirections.length];
}
+ private StaticLayout(Builder b) {
+ super((b.mEllipsize == null)
+ ? b.mText
+ : (b.mText instanceof Spanned)
+ ? new SpannedEllipsizer(b.mText)
+ : new Ellipsizer(b.mText),
+ b.mPaint, b.mWidth, b.mAlignment, b.mSpacingMult, b.mSpacingAdd);
+
+ if (b.mEllipsize != null) {
+ Ellipsizer e = (Ellipsizer) getText();
+
+ e.mLayout = this;
+ e.mWidth = b.mEllipsizedWidth;
+ e.mMethod = b.mEllipsize;
+ mEllipsizedWidth = b.mEllipsizedWidth;
+
+ mColumns = COLUMNS_ELLIPSIZE;
+ } else {
+ mColumns = COLUMNS_NORMAL;
+ mEllipsizedWidth = b.mWidth;
+ }
+
+ mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
+ mLines = new int[mLineDirections.length];
+ mMaximumVisibleLineCount = b.mMaxLines;
+
+ generate(b, b.mIncludePad, b.mIncludePad);
+ }
+
/* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
CharSequence source = b.mText;
int bufStart = b.mStart;
@@ -476,10 +503,9 @@
}
}
- int breakStrategy = 0; // 0 = kBreakStrategy_Greedy
nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
firstWidth, firstWidthLineCount, restWidth,
- variableTabStops, TAB_INCREMENT, breakStrategy);
+ variableTabStops, TAB_INCREMENT, b.mBreakStrategy);
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
@@ -531,7 +557,7 @@
int[] breaks = lineBreaks.breaks;
float[] lineWidths = lineBreaks.widths;
- boolean[] flags = lineBreaks.flags;
+ int[] flags = lineBreaks.flags;
// here is the offset of the starting character of the line we are currently measuring
int here = paraStart;
@@ -617,7 +643,7 @@
fm.top, fm.bottom,
v,
spacingmult, spacingadd, null,
- null, fm, false,
+ null, fm, 0,
needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd,
includepad, trackpad, null,
null, bufStart, ellipsize,
@@ -629,7 +655,7 @@
int above, int below, int top, int bottom, int v,
float spacingmult, float spacingadd,
LineHeightSpan[] chooseHt, int[] chooseHtv,
- Paint.FontMetricsInt fm, boolean hasTabOrEmoji,
+ Paint.FontMetricsInt fm, int flags,
boolean needMultiply, byte[] chdirs, int dir,
boolean easy, int bufEnd, boolean includePad,
boolean trackPad, char[] chs,
@@ -722,8 +748,10 @@
lines[off + mColumns + START] = end;
lines[off + mColumns + TOP] = v;
- if (hasTabOrEmoji)
- lines[off + TAB] |= TAB_MASK;
+ // TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining
+ // one bit for start field
+ lines[off + TAB] |= flags & TAB_MASK;
+ lines[off + HYPHEN] = flags;
lines[off + DIR] |= dir << DIR_SHIFT;
Directions linedirs = DIRS_ALL_LEFT_TO_RIGHT;
@@ -942,6 +970,14 @@
return mBottomPadding;
}
+ /**
+ * @hide
+ */
+ @Override
+ public int getHyphen(int line) {
+ return mLines[mColumns * line + HYPHEN] & 0xff;
+ }
+
@Override
public int getEllipsisCount(int line) {
if (mColumns < COLUMNS_ELLIPSIZE) {
@@ -968,7 +1004,10 @@
private static native long nNewBuilder();
private static native void nFreeBuilder(long nativePtr);
private static native void nFinishBuilder(long nativePtr);
- private static native void nSetLocale(long nativePtr, String locale);
+
+ /* package */ static native long nLoadHyphenator(String patternData);
+
+ private static native void nSetLocale(long nativePtr, String locale, long nativeHyphenator);
// Set up paragraph text and settings; done as one big method to minimize jni crossings
private static native void nSetupParagraph(long nativePtr, char[] text, int length,
@@ -991,22 +1030,23 @@
// to reduce the number of JNI calls in the common case where the
// arrays do not have to be resized
private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
- int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);
+ int[] recycleBreaks, float[] recycleWidths, int[] recycleFlags, int recycleLength);
private int mLineCount;
private int mTopPadding, mBottomPadding;
private int mColumns;
private int mEllipsizedWidth;
- private static final int COLUMNS_NORMAL = 3;
- private static final int COLUMNS_ELLIPSIZE = 5;
+ private static final int COLUMNS_NORMAL = 4;
+ private static final int COLUMNS_ELLIPSIZE = 6;
private static final int START = 0;
private static final int DIR = START;
private static final int TAB = START;
private static final int TOP = 1;
private static final int DESCENT = 2;
- private static final int ELLIPSIS_START = 3;
- private static final int ELLIPSIS_COUNT = 4;
+ private static final int HYPHEN = 3;
+ private static final int ELLIPSIS_START = 4;
+ private static final int ELLIPSIS_COUNT = 5;
private int[] mLines;
private Directions[] mLineDirections;
@@ -1028,7 +1068,7 @@
private static final int INITIAL_SIZE = 16;
public int[] breaks = new int[INITIAL_SIZE];
public float[] widths = new float[INITIAL_SIZE];
- public boolean[] flags = new boolean[INITIAL_SIZE]; // hasTabOrEmoji
+ public int[] flags = new int[INITIAL_SIZE]; // hasTabOrEmoji
// breaks, widths, and flags should all have the same length
}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 4725581..479242c 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -955,6 +955,10 @@
span.updateDrawState(wp);
}
+ // Only draw hyphen on last run in line
+ if (jnext < mLen) {
+ wp.setHyphenEdit(0);
+ }
x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x,
top, y, bottom, fmi, needWidth || jnext < measureLimit);
}
diff --git a/core/java/android/util/DebugUtils.java b/core/java/android/util/DebugUtils.java
index 84d9ce8..c44f42b 100644
--- a/core/java/android/util/DebugUtils.java
+++ b/core/java/android/util/DebugUtils.java
@@ -17,8 +17,10 @@
package android.util;
import java.io.PrintWriter;
-import java.lang.reflect.Method;
+import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.util.Locale;
/**
@@ -203,4 +205,57 @@
outBuilder.append(suffix);
return outBuilder.toString();
}
+
+ /**
+ * Use prefixed constants (static final values) on given class to turn value
+ * into human-readable string.
+ *
+ * @hide
+ */
+ public static String valueToString(Class<?> clazz, String prefix, int value) {
+ for (Field field : clazz.getDeclaredFields()) {
+ final int modifiers = field.getModifiers();
+ if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)
+ && field.getType().equals(int.class) && field.getName().startsWith(prefix)) {
+ try {
+ if (value == field.getInt(null)) {
+ return field.getName().substring(prefix.length());
+ }
+ } catch (IllegalAccessException ignored) {
+ }
+ }
+ }
+ return Integer.toString(value);
+ }
+
+ /**
+ * Use prefixed constants (static final values) on given class to turn flags
+ * into human-readable string.
+ *
+ * @hide
+ */
+ public static String flagsToString(Class<?> clazz, String prefix, int flags) {
+ final StringBuilder res = new StringBuilder();
+
+ for (Field field : clazz.getDeclaredFields()) {
+ final int modifiers = field.getModifiers();
+ if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)
+ && field.getType().equals(int.class) && field.getName().startsWith(prefix)) {
+ try {
+ final int value = field.getInt(null);
+ if ((flags & value) != 0) {
+ flags &= ~value;
+ res.append(field.getName().substring(prefix.length())).append('|');
+ }
+ } catch (IllegalAccessException ignored) {
+ }
+ }
+ }
+ if (flags != 0 || res.length() == 0) {
+ res.append(Integer.toHexString(flags));
+ } else {
+ res.deleteCharAt(res.length() - 1);
+ }
+ return res.toString();
+ }
}
diff --git a/core/java/android/view/IGraphicsStats.aidl b/core/java/android/view/IGraphicsStats.aidl
new file mode 100644
index 0000000..c235eb2
--- /dev/null
+++ b/core/java/android/view/IGraphicsStats.aidl
@@ -0,0 +1,26 @@
+/**
+ * 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;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * @hide
+ */
+interface IGraphicsStats {
+ ParcelFileDescriptor requestBufferForProcess(String packageName, IBinder token);
+}
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 6508cca..5cf2c5c 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -130,6 +130,7 @@
private float mFocusY;
private boolean mQuickScaleEnabled;
+ private boolean mButtonScaleEnabled;
private float mCurrSpan;
private float mPrevSpan;
@@ -151,14 +152,17 @@
private int mTouchHistoryDirection;
private long mTouchHistoryLastAcceptedTime;
private int mTouchMinMajor;
- private MotionEvent mDoubleTapEvent;
- private int mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
private final Handler mHandler;
+ private float mAnchoredScaleStartX;
+ private float mAnchoredScaleStartY;
+ private int mAnchoredScaleMode = ANCHORED_SCALE_MODE_NONE;
+
private static final long TOUCH_STABILIZE_TIME = 128; // ms
- private static final int DOUBLE_TAP_MODE_NONE = 0;
- private static final int DOUBLE_TAP_MODE_IN_PROGRESS = 1;
private static final float SCALE_FACTOR = .5f;
+ private static final int ANCHORED_SCALE_MODE_NONE = 0;
+ private static final int ANCHORED_SCALE_MODE_DOUBLE_TAP = 1;
+ private static final int ANCHORED_SCALE_MODE_BUTTON = 2;
/**
@@ -310,8 +314,17 @@
mGestureDetector.onTouchEvent(event);
}
+ final int count = event.getPointerCount();
+ final int toolType = event.getToolType(0);
+ final boolean isButtonTool = toolType == MotionEvent.TOOL_TYPE_STYLUS
+ || toolType == MotionEvent.TOOL_TYPE_MOUSE;
+ final boolean isAnchoredScaleButtonDown = isButtonTool && (count == 1)
+ && (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0;
+
+ final boolean anchoredScaleCancelled =
+ mAnchoredScaleMode == ANCHORED_SCALE_MODE_BUTTON && !isAnchoredScaleButtonDown;
final boolean streamComplete = action == MotionEvent.ACTION_UP ||
- action == MotionEvent.ACTION_CANCEL;
+ action == MotionEvent.ACTION_CANCEL || anchoredScaleCancelled;
if (action == MotionEvent.ACTION_DOWN || streamComplete) {
// Reset any scale in progress with the listener.
@@ -321,11 +334,11 @@
mListener.onScaleEnd(this);
mInProgress = false;
mInitialSpan = 0;
- mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
- } else if (mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS && streamComplete) {
+ mAnchoredScaleMode = ANCHORED_SCALE_MODE_NONE;
+ } else if (inAnchoredScaleMode() && streamComplete) {
mInProgress = false;
mInitialSpan = 0;
- mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
+ mAnchoredScaleMode = ANCHORED_SCALE_MODE_NONE;
}
if (streamComplete) {
@@ -334,25 +347,32 @@
}
}
+ if (!mInProgress && mButtonScaleEnabled && !inAnchoredScaleMode()
+ && !streamComplete && isAnchoredScaleButtonDown) {
+ // Start of a button scale gesture
+ mAnchoredScaleStartX = event.getX();
+ mAnchoredScaleStartY = event.getY();
+ mAnchoredScaleMode = ANCHORED_SCALE_MODE_BUTTON;
+ mInitialSpan = 0;
+ }
+
final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
action == MotionEvent.ACTION_POINTER_UP ||
- action == MotionEvent.ACTION_POINTER_DOWN;
-
+ action == MotionEvent.ACTION_POINTER_DOWN || anchoredScaleCancelled;
final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
final int skipIndex = pointerUp ? event.getActionIndex() : -1;
// Determine focal point
float sumX = 0, sumY = 0;
- final int count = event.getPointerCount();
final int div = pointerUp ? count - 1 : count;
final float focusX;
final float focusY;
- if (mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS) {
- // In double tap mode, the focal pt is always where the double tap
- // gesture started
- focusX = mDoubleTapEvent.getX();
- focusY = mDoubleTapEvent.getY();
+ if (inAnchoredScaleMode()) {
+ // In anchored scale mode, the focal pt is always where the double tap
+ // or button down gesture started
+ focusX = mAnchoredScaleStartX;
+ focusY = mAnchoredScaleStartY;
if (event.getY() < focusY) {
mEventBeforeOrAboveStartingGestureEvent = true;
} else {
@@ -390,7 +410,7 @@
final float spanX = devX * 2;
final float spanY = devY * 2;
final float span;
- if (inDoubleTapMode()) {
+ if (inAnchoredScaleMode()) {
span = spanY;
} else {
span = (float) Math.hypot(spanX, spanY);
@@ -402,11 +422,10 @@
final boolean wasInProgress = mInProgress;
mFocusX = focusX;
mFocusY = focusY;
- if (!inDoubleTapMode() && mInProgress && (span < mMinSpan || configChanged)) {
+ if (!inAnchoredScaleMode() && mInProgress && (span < mMinSpan || configChanged)) {
mListener.onScaleEnd(this);
mInProgress = false;
mInitialSpan = span;
- mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
}
if (configChanged) {
mPrevSpanX = mCurrSpanX = spanX;
@@ -414,7 +433,7 @@
mInitialSpan = mPrevSpan = mCurrSpan = span;
}
- final int minSpan = inDoubleTapMode() ? mSpanSlop : mMinSpan;
+ final int minSpan = inAnchoredScaleMode() ? mSpanSlop : mMinSpan;
if (!mInProgress && span >= minSpan &&
(wasInProgress || Math.abs(span - mInitialSpan) > mSpanSlop)) {
mPrevSpanX = mCurrSpanX = spanX;
@@ -447,9 +466,8 @@
return true;
}
-
- private boolean inDoubleTapMode() {
- return mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS;
+ private boolean inAnchoredScaleMode() {
+ return mAnchoredScaleMode != ANCHORED_SCALE_MODE_NONE;
}
/**
@@ -466,8 +484,9 @@
@Override
public boolean onDoubleTap(MotionEvent e) {
// Double tap: start watching for a swipe
- mDoubleTapEvent = e;
- mDoubleTapMode = DOUBLE_TAP_MODE_IN_PROGRESS;
+ mAnchoredScaleStartX = e.getX();
+ mAnchoredScaleStartY = e.getY();
+ mAnchoredScaleMode = ANCHORED_SCALE_MODE_DOUBLE_TAP;
return true;
}
};
@@ -484,6 +503,27 @@
}
/**
+ * Sets whether the associates {@link OnScaleGestureListener} should receive onScale callbacks
+ * when the user presses a {@value MotionEvent#BUTTON_SECONDARY} (right mouse button, stylus
+ * first button) and drags the pointer on the screen. Note that this is enabled by default if
+ * the app targets API 23 and newer.
+ *
+ * @param scales true to enable stylus or mouse scaling, false to disable.
+ */
+ public void setSecondaryButtonScaleEnabled(boolean scales) {
+ mButtonScaleEnabled = scales;
+ }
+
+ /**
+ * Return whether the button scale gesture, in which the user presses a
+ * {@value MotionEvent#BUTTON_SECONDARY} (right mouse button, stylus first button) and drags the
+ * pointer on the screen, should perform scaling. {@see #setButtonScaleEnabled(boolean)}.
+ */
+ public boolean isSecondaryButtonScaleEnabled() {
+ return mButtonScaleEnabled;
+ }
+
+ /**
* Returns {@code true} if a scale gesture is in progress.
*/
public boolean isInProgress() {
@@ -586,7 +626,7 @@
* @return The current scaling factor.
*/
public float getScaleFactor() {
- if (inDoubleTapMode()) {
+ if (inAnchoredScaleMode()) {
// Drag is moving up; the further away from the gesture
// start, the smaller the span should be, the closer,
// the larger the span, and therefore the larger the scale
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 031be07..87d5d9a 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -23,7 +23,9 @@
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Binder;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.Trace;
@@ -124,7 +126,7 @@
mRootNode.setClipToBounds(false);
mNativeProxy = nCreateProxy(translucent, rootNodePtr);
- AtlasInitializer.sInstance.init(context, mNativeProxy);
+ ProcessInitializer.sInstance.init(context, mNativeProxy);
loadSystemProperties();
}
@@ -410,15 +412,44 @@
nTrimMemory(level);
}
- private static class AtlasInitializer {
- static AtlasInitializer sInstance = new AtlasInitializer();
+ public static void dumpProfileData(byte[] data, FileDescriptor fd) {
+ nDumpProfileData(data, fd);
+ }
+
+ private static class ProcessInitializer {
+ static ProcessInitializer sInstance = new ProcessInitializer();
+ static IGraphicsStats sGraphicsStatsService;
+ private static IBinder sProcToken;
private boolean mInitialized = false;
- private AtlasInitializer() {}
+ private ProcessInitializer() {}
synchronized void init(Context context, long renderProxy) {
if (mInitialized) return;
+ mInitialized = true;
+ initGraphicsStats(context, renderProxy);
+ initAssetAtlas(context, renderProxy);
+ }
+
+ private static void initGraphicsStats(Context context, long renderProxy) {
+ IBinder binder = ServiceManager.getService("graphicsstats");
+ if (binder == null) return;
+
+ sGraphicsStatsService = IGraphicsStats.Stub.asInterface(binder);
+ sProcToken = new Binder();
+ try {
+ final String pkg = context.getApplicationInfo().packageName;
+ ParcelFileDescriptor pfd = sGraphicsStatsService.
+ requestBufferForProcess(pkg, sProcToken);
+ nSetProcessStatsBuffer(renderProxy, pfd.getFd());
+ pfd.close();
+ } catch (Exception e) {
+ Log.w(LOG_TAG, "Could not acquire gfx stats buffer", e);
+ }
+ }
+
+ private static void initAssetAtlas(Context context, long renderProxy) {
IBinder binder = ServiceManager.getService("assetatlas");
if (binder == null) return;
@@ -432,7 +463,6 @@
// TODO Remove after fixing b/15425820
validateMap(context, map);
nSetAtlas(renderProxy, buffer, map);
- mInitialized = true;
}
// If IAssetAtlas is not the same class as the IBinder
// we are using a remote service and we can safely
@@ -477,6 +507,7 @@
static native void setupShadersDiskCache(String cacheFile);
private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
+ private static native void nSetProcessStatsBuffer(long nativeProxy, int fd);
private static native long nCreateRootRenderNode();
private static native long nCreateProxy(boolean translucent, long rootRenderNode);
@@ -514,4 +545,5 @@
private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
@DumpFlags int dumpFlags);
+ private static native void nDumpProfileData(byte[] data, FileDescriptor fd);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cfcc6fe..a69384a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9959,6 +9959,8 @@
* @param oldt Previous vertical scroll origin.
*/
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ notifySubtreeAccessibilityStateChangedIfNeeded();
+
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
postSendViewScrolledAccessibilityEventCallback();
}
@@ -11162,6 +11164,7 @@
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
+ notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 294174a..4158340 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6268,41 +6268,79 @@
case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: {
- if (mAccessibilityFocusedHost != null && mAccessibilityFocusedVirtualView != null) {
- // We care only for changes rooted in the focused host.
- final long eventSourceId = event.getSourceNodeId();
- final int hostViewId = AccessibilityNodeInfo.getAccessibilityViewId(
- eventSourceId);
- if (hostViewId != mAccessibilityFocusedHost.getAccessibilityViewId()) {
- break;
- }
-
- // We only care about changes that may change the virtual focused view bounds.
- final int changes = event.getContentChangeTypes();
- if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) != 0
- || changes == AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
- AccessibilityNodeProvider provider = mAccessibilityFocusedHost
- .getAccessibilityNodeProvider();
- if (provider != null) {
- final int virtualChildId = AccessibilityNodeInfo.getVirtualDescendantId(
- mAccessibilityFocusedVirtualView.getSourceNodeId());
- if (virtualChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
- mAccessibilityFocusedVirtualView = provider
- .createAccessibilityNodeInfo(
- AccessibilityNodeProvider.HOST_VIEW_ID);
- } else {
- mAccessibilityFocusedVirtualView = provider
- .createAccessibilityNodeInfo(virtualChildId);
- }
- }
- }
- }
+ handleWindowContentChangedEvent(event);
} break;
}
mAccessibilityManager.sendAccessibilityEvent(event);
return true;
}
+ /**
+ * Updates the focused virtual view, when necessary, in response to a
+ * content changed event.
+ * <p>
+ * This is necessary to get updated bounds after a position change.
+ *
+ * @param event an accessibility event of type
+ * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
+ */
+ private void handleWindowContentChangedEvent(AccessibilityEvent event) {
+ // No virtual view focused, nothing to do here.
+ if (mAccessibilityFocusedHost == null || mAccessibilityFocusedVirtualView == null) {
+ return;
+ }
+
+ // If we have a node but no provider, abort.
+ final AccessibilityNodeProvider provider =
+ mAccessibilityFocusedHost.getAccessibilityNodeProvider();
+ if (provider == null) {
+ // TODO: Should we clear the focused virtual view?
+ return;
+ }
+
+ // We only care about change types that may affect the bounds of the
+ // focused virtual view.
+ final int changes = event.getContentChangeTypes();
+ if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0
+ && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
+ return;
+ }
+
+ final long eventSourceNodeId = event.getSourceNodeId();
+ final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
+
+ // Search up the tree for subtree containment.
+ boolean hostInSubtree = false;
+ View root = mAccessibilityFocusedHost;
+ while (root != null && !hostInSubtree) {
+ if (changedViewId == root.getAccessibilityViewId()) {
+ hostInSubtree = true;
+ } else {
+ final ViewParent parent = root.getParent();
+ if (parent instanceof View) {
+ root = (View) parent;
+ } else {
+ root = null;
+ }
+ }
+ }
+
+ // We care only about changes in subtrees containing the host view.
+ if (!hostInSubtree) {
+ return;
+ }
+
+ final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
+ int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
+ if (focusedChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ // TODO: Should we clear the focused virtual view?
+ focusedChildId = AccessibilityNodeProvider.HOST_VIEW_ID;
+ }
+
+ // Refresh the node for the focused virtual view.
+ mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
+ }
+
@Override
public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
postSendWindowContentChangedCallback(source, changeType);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 77082b0..ec527d5 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1562,7 +1562,7 @@
}
/**
- * Sets whether this node is visible to the user.
+ * Gets whether this node is visible to the user.
*
* @return Whether the node is visible to the user.
*/
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 53c7e04..8a2b3fa 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -200,8 +200,6 @@
public static final int ERROR_FILE_NOT_FOUND = -14;
/** Too many requests during this load */
public static final int ERROR_TOO_MANY_REQUESTS = -15;
- /** Request blocked by the browser */
- public static final int ERROR_BLOCKED = -16;
/**
* Report an error to the host application. These errors are unrecoverable
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 1716dbd..45eee34 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -40,8 +40,10 @@
* @attr ref android.R.styleable#AnalogClock_dial
* @attr ref android.R.styleable#AnalogClock_hand_hour
* @attr ref android.R.styleable#AnalogClock_hand_minute
+ * @deprecated This widget is no longer supported.
*/
@RemoteView
+@Deprecated
public class AnalogClock extends View {
private Time mCalendar;
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 7b8a979..a157087 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -49,7 +49,6 @@
* A delegate for picking up a date (day / month / year).
*/
class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
-
private static final int USE_LOCALE = 0;
private static final int UNINITIALIZED = -1;
@@ -61,9 +60,9 @@
private static final int ANIMATION_DURATION = 300;
- public static final int[] ATTRS_TEXT_COLOR = new int[]{com.android.internal.R.attr.textColor};
-
- public static final int[] ATTRS_DISABLED_ALPHA = new int[]{
+ private static final int[] ATTRS_TEXT_COLOR = new int[] {
+ com.android.internal.R.attr.textColor};
+ private static final int[] ATTRS_DISABLED_ALPHA = new int[] {
com.android.internal.R.attr.disabledAlpha};
private SimpleDateFormat mYearFormat;
@@ -157,6 +156,8 @@
header.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground));
}
+ a.recycle();
+
// Set up picker container.
mAnimator = (ViewAnimator) mContainer.findViewById(R.id.animator);
@@ -174,32 +175,10 @@
mYearPickerView.setDate(mCurrentDate.getTimeInMillis());
mYearPickerView.setOnYearSelectedListener(mOnYearSelectedListener);
- final int yearTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_yearListItemTextAppearance, 0);
- if (yearTextAppearanceResId != 0) {
- mYearPickerView.setYearTextAppearance(yearTextAppearanceResId);
- }
-
- final int yearActivatedTextAppearanceResId = a.getResourceId(
- R.styleable.DatePicker_yearListItemActivatedTextAppearance, 0);
- if (yearActivatedTextAppearanceResId != 0) {
- mYearPickerView.setYearActivatedTextAppearance(yearActivatedTextAppearanceResId);
- }
-
- a.recycle();
-
// Set up content descriptions.
mSelectDay = res.getString(R.string.select_day);
mSelectYear = res.getString(R.string.select_year);
- final Animation inAnim = new AlphaAnimation(0, 1);
- inAnim.setDuration(ANIMATION_DURATION);
- mAnimator.setInAnimation(inAnim);
-
- final Animation outAnim = new AlphaAnimation(1, 0);
- outAnim.setDuration(ANIMATION_DURATION);
- mAnimator.setOutAnimation(outAnim);
-
// Initialize for current locale. This also initializes the date, so no
// need to call onDateChanged.
onLocaleChanged(mCurrentLocale);
diff --git a/core/java/android/widget/DayPickerAdapter.java b/core/java/android/widget/DayPickerAdapter.java
index 4f9f09e..9a4b6f5 100644
--- a/core/java/android/widget/DayPickerAdapter.java
+++ b/core/java/android/widget/DayPickerAdapter.java
@@ -18,10 +18,15 @@
import com.android.internal.widget.PagerAdapter;
+import android.annotation.IdRes;
+import android.annotation.LayoutRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.util.SparseArray;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SimpleMonthView.OnDayClickListener;
@@ -37,9 +42,13 @@
private final Calendar mMinDate = Calendar.getInstance();
private final Calendar mMaxDate = Calendar.getInstance();
- private final SparseArray<SimpleMonthView> mItems = new SparseArray<>();
+ private final SparseArray<ViewHolder> mItems = new SparseArray<>();
- private Calendar mSelectedDay = Calendar.getInstance();
+ private final LayoutInflater mInflater;
+ private final int mLayoutResId;
+ private final int mCalendarViewId;
+
+ private Calendar mSelectedDay = null;
private int mMonthTextAppearance;
private int mDayOfWeekTextAppearance;
@@ -51,19 +60,29 @@
private OnDaySelectedListener mOnDaySelectedListener;
+ private int mCount;
private int mFirstDayOfWeek;
- public DayPickerAdapter(Context context) {
+ public DayPickerAdapter(@NonNull Context context, @LayoutRes int layoutResId,
+ @IdRes int calendarViewId) {
+ mInflater = LayoutInflater.from(context);
+ mLayoutResId = layoutResId;
+ mCalendarViewId = calendarViewId;
+
final TypedArray ta = context.obtainStyledAttributes(new int[] {
com.android.internal.R.attr.colorControlHighlight});
mDayHighlightColor = ta.getColorStateList(0);
ta.recycle();
}
- public void setRange(Calendar min, Calendar max) {
+ public void setRange(@NonNull Calendar min, @NonNull Calendar max) {
mMinDate.setTimeInMillis(min.getTimeInMillis());
mMaxDate.setTimeInMillis(max.getTimeInMillis());
+ final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
+ final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
+ mCount = diffMonth + MONTHS_IN_YEAR * diffYear + 1;
+
// Positions are now invalid, clear everything and start over.
notifyDataSetChanged();
}
@@ -80,7 +99,7 @@
// Update displayed views.
final int count = mItems.size();
for (int i = 0; i < count; i++) {
- final SimpleMonthView monthView = mItems.valueAt(i);
+ final SimpleMonthView monthView = mItems.valueAt(i).calendar;
monthView.setFirstDayOfWeek(weekStart);
}
}
@@ -94,23 +113,25 @@
*
* @param day the selected day
*/
- public void setSelectedDay(Calendar day) {
+ public void setSelectedDay(@Nullable Calendar day) {
final int oldPosition = getPositionForDay(mSelectedDay);
final int newPosition = getPositionForDay(day);
// Clear the old position if necessary.
- if (oldPosition != newPosition) {
- final SimpleMonthView oldMonthView = mItems.get(oldPosition, null);
+ if (oldPosition != newPosition && oldPosition >= 0) {
+ final ViewHolder oldMonthView = mItems.get(oldPosition, null);
if (oldMonthView != null) {
- oldMonthView.setSelectedDay(-1);
+ oldMonthView.calendar.setSelectedDay(-1);
}
}
// Set the new position.
- final SimpleMonthView newMonthView = mItems.get(newPosition, null);
- if (newMonthView != null) {
- final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
- newMonthView.setSelectedDay(dayOfMonth);
+ if (newPosition >= 0) {
+ final ViewHolder newMonthView = mItems.get(newPosition, null);
+ if (newMonthView != null) {
+ final int dayOfMonth = day.get(Calendar.DAY_OF_MONTH);
+ newMonthView.calendar.setSelectedDay(dayOfMonth);
+ }
}
mSelectedDay = day;
@@ -155,14 +176,13 @@
@Override
public int getCount() {
- final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
- final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
- return diffMonth + MONTHS_IN_YEAR * diffYear + 1;
+ return mCount;
}
@Override
public boolean isViewFromObject(View view, Object object) {
- return view == object;
+ final ViewHolder holder = (ViewHolder) object;
+ return view == holder.container;
}
private int getMonthForPosition(int position) {
@@ -173,7 +193,11 @@
return position / MONTHS_IN_YEAR + mMinDate.get(Calendar.YEAR);
}
- private int getPositionForDay(Calendar day) {
+ private int getPositionForDay(@Nullable Calendar day) {
+ if (day == null) {
+ return -1;
+ }
+
final int yearOffset = (day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR));
final int monthOffset = (day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH));
return yearOffset * MONTHS_IN_YEAR + monthOffset;
@@ -181,7 +205,9 @@
@Override
public Object instantiateItem(ViewGroup container, int position) {
- final SimpleMonthView v = new SimpleMonthView(container.getContext());
+ final View itemView = mInflater.inflate(mLayoutResId, container, false);
+
+ final SimpleMonthView v = (SimpleMonthView) itemView.findViewById(mCalendarViewId);
v.setOnDayClickListener(mOnDayClickListener);
v.setMonthTextAppearance(mMonthTextAppearance);
v.setDayOfWeekTextAppearance(mDayOfWeekTextAppearance);
@@ -205,7 +231,7 @@
final int year = getYearForPosition(position);
final int selectedDay;
- if (mSelectedDay.get(Calendar.MONTH) == month) {
+ if (mSelectedDay != null && mSelectedDay.get(Calendar.MONTH) == month) {
selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH);
} else {
selectedDay = -1;
@@ -227,33 +253,34 @@
v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
enabledDayRangeStart, enabledDayRangeEnd);
+ v.setPrevEnabled(position > 0);
+ v.setNextEnabled(position < mCount - 1);
- mItems.put(position, v);
+ final ViewHolder holder = new ViewHolder(position, itemView, v);
+ mItems.put(position, holder);
- container.addView(v);
+ container.addView(itemView);
- return v;
+ return holder;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView(mItems.get(position));
+ final ViewHolder holder = (ViewHolder) object;
+ container.removeView(holder.container);
mItems.remove(position);
}
@Override
public int getItemPosition(Object object) {
- final int index = mItems.indexOfValue((SimpleMonthView) object);
- if (index < 0) {
- return mItems.keyAt(index);
- }
- return -1;
+ final ViewHolder holder = (ViewHolder) object;
+ return holder.position;
}
@Override
public CharSequence getPageTitle(int position) {
- final SimpleMonthView v = mItems.get(position);
+ final SimpleMonthView v = mItems.get(position).calendar;
if (v != null) {
return v.getTitle();
}
@@ -275,9 +302,29 @@
}
}
}
+
+ @Override
+ public void onNavigationClick(SimpleMonthView view, int direction, boolean animate) {
+ if (mOnDaySelectedListener != null) {
+ mOnDaySelectedListener.onNavigationClick(DayPickerAdapter.this, direction, animate);
+ }
+ }
};
+ private static class ViewHolder {
+ public final int position;
+ public final View container;
+ public final SimpleMonthView calendar;
+
+ public ViewHolder(int position, View container, SimpleMonthView calendar) {
+ this.position = position;
+ this.container = container;
+ this.calendar = calendar;
+ }
+ }
+
public interface OnDaySelectedListener {
public void onDaySelected(DayPickerAdapter view, Calendar day);
+ public void onNavigationClick(DayPickerAdapter view, int direction, boolean animate);
}
}
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index a7ae926..ec2528f 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -88,7 +88,8 @@
a.recycle();
// Set up adapter.
- mAdapter = new DayPickerAdapter(context);
+ mAdapter = new DayPickerAdapter(context,
+ R.layout.date_picker_month_item_material, R.id.month_view);
mAdapter.setMonthTextAppearance(monthTextAppearanceResId);
mAdapter.setDayOfWeekTextAppearance(dayOfWeekTextAppearanceResId);
mAdapter.setDayTextAppearance(dayTextAppearanceResId);
@@ -128,6 +129,14 @@
mOnDaySelectedListener.onDaySelected(DayPickerView.this, day);
}
}
+
+ @Override
+ public void onNavigationClick(DayPickerAdapter view, int direction, boolean animate) {
+ // ViewPager clamps input values, so we don't need to worry
+ // about passing invalid indices.
+ final int nextItem = getCurrentItem() + direction;
+ setCurrentItem(nextItem, animate);
+ }
});
}
@@ -178,7 +187,6 @@
* @param setSelected whether to set the specified day as selected
*/
private void setDate(long timeInMillis, boolean animate, boolean setSelected) {
- // Set the selected day
if (setSelected) {
mSelectedDay.setTimeInMillis(timeInMillis);
}
@@ -187,6 +195,9 @@
if (position != getCurrentItem()) {
setCurrentItem(position, animate);
}
+
+ mTempCalendar.setTimeInMillis(timeInMillis);
+ mAdapter.setSelectedDay(mTempCalendar);
}
public long getDate() {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b5e9a0b..32b99a8 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -16,18 +16,6 @@
package android.widget;
-import android.content.UndoManager;
-import android.content.UndoOperation;
-import android.content.UndoOwner;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.InputFilter;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.GrowingArrayUtils;
-import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.widget.EditableInputConnection;
-
import android.R;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
@@ -35,6 +23,9 @@
import android.content.ClipData.Item;
import android.content.Context;
import android.content.Intent;
+import android.content.UndoManager;
+import android.content.UndoOperation;
+import android.content.UndoOwner;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -46,13 +37,17 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.ExtractEditText;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.ParcelableParcel;
import android.os.SystemClock;
import android.provider.Settings;
import android.text.DynamicLayout;
import android.text.Editable;
+import android.text.InputFilter;
import android.text.InputType;
import android.text.Layout;
import android.text.ParcelableSpan;
@@ -105,6 +100,11 @@
import android.widget.TextView.Drawables;
import android.widget.TextView.OnEditorActionListener;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.widget.EditableInputConnection;
+
import java.text.BreakIterator;
import java.util.Arrays;
import java.util.Comparator;
@@ -2939,7 +2939,27 @@
* The default callback provides a subset of Select All, Cut, Copy and Paste actions, depending
* on which of these this TextView supports.
*/
- private class SelectionActionModeCallback implements ActionMode.Callback {
+ private class SelectionActionModeCallback extends ActionMode.Callback2 {
+ private final Path mSelectionPath = new Path();
+ private final RectF mSelectionBounds = new RectF();
+
+ private int mSelectionHandleHeight;
+ private int mInsertionHandleHeight;
+
+ public SelectionActionModeCallback() {
+ SelectionModifierCursorController selectionController = getSelectionController();
+ if (selectionController.mStartHandle == null) {
+ selectionController.initDrawables();
+ selectionController.initHandles();
+ }
+ mSelectionHandleHeight = Math.max(
+ mSelectHandleLeft.getMinimumHeight(), mSelectHandleRight.getMinimumHeight());
+ InsertionPointCursorController insertionController = getInsertionController();
+ if (insertionController != null) {
+ insertionController.getHandle();
+ mInsertionHandleHeight = mSelectHandleCenter.getMinimumHeight();
+ }
+ }
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
@@ -2956,13 +2976,6 @@
mode.setSubtitle(null);
mode.setTitleOptionalHint(true);
- menu.add(0, TextView.ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
- setIcon(styledAttributes.getResourceId(
- R.styleable.SelectionModeDrawables_actionModeSelectAllDrawable, 0)).
- setAlphabeticShortcut('a').
- setShowAsAction(
- MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
-
if (mTextView.canCut()) {
menu.add(0, TextView.ID_CUT, 0, com.android.internal.R.string.cut).
setIcon(styledAttributes.getResourceId(
@@ -2990,6 +3003,13 @@
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
}
+ menu.add(0, TextView.ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
+ setIcon(styledAttributes.getResourceId(
+ R.styleable.SelectionModeDrawables_actionModeSelectAllDrawable, 0)).
+ setAlphabeticShortcut('a').
+ setShowAsAction(
+ MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+
if (mTextView.isSuggestionsEnabled() && isCursorInsideSuggestionSpan()) {
menu.add(0, TextView.ID_REPLACE, 0, com.android.internal.R.string.replace).
setShowAsAction(
@@ -3057,6 +3077,40 @@
mSelectionActionMode = null;
}
+
+ @Override
+ public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
+ if (!view.equals(mTextView) || mTextView.getLayout() == null) {
+ super.onGetContentRect(mode, view, outRect);
+ return;
+ }
+ if (mTextView.getSelectionStart() != mTextView.getSelectionEnd()) {
+ // We have a selection.
+ mSelectionPath.reset();
+ mTextView.getLayout().getSelectionPath(
+ mTextView.getSelectionStart(), mTextView.getSelectionEnd(), mSelectionPath);
+ mSelectionPath.computeBounds(mSelectionBounds, true);
+ mSelectionBounds.bottom += mSelectionHandleHeight;
+ } else {
+ // We have a single cursor.
+ int line = mTextView.getLayout().getLineForOffset(mTextView.getSelectionStart());
+ float primaryHorizontal =
+ mTextView.getLayout().getPrimaryHorizontal(mTextView.getSelectionStart());
+ mSelectionBounds.set(
+ primaryHorizontal,
+ mTextView.getLayout().getLineTop(line),
+ primaryHorizontal + 1,
+ mTextView.getLayout().getLineTop(line + 1) + mInsertionHandleHeight);
+ }
+ // Take TextView's padding and scroll into account.
+ int textHorizontalOffset = mTextView.viewportToContentHorizontalOffset();
+ int textVerticalOffset = mTextView.viewportToContentVerticalOffset();
+ outRect.set(
+ (int) Math.floor(mSelectionBounds.left + textHorizontalOffset),
+ (int) Math.floor(mSelectionBounds.top + textVerticalOffset),
+ (int) Math.ceil(mSelectionBounds.right + textHorizontalOffset),
+ (int) Math.ceil(mSelectionBounds.bottom + textVerticalOffset));
+ }
}
private void onReplace() {
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 349f3f0..a50941b 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -815,12 +815,12 @@
mContext = context;
mIntent = intent;
- mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
-
- mLayoutInflater = LayoutInflater.from(context);
if (mIntent == null) {
throw new IllegalArgumentException("Non-null Intent must be specified.");
}
+
+ mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
+ mLayoutInflater = LayoutInflater.from(context);
mRequestedViews = new RemoteViewsFrameLayoutRefSet();
// Strip the previously injected app widget id from service intent
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 4e5a39a..d9f1f0e 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -26,6 +26,7 @@
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextPaint;
import android.text.format.DateFormat;
@@ -59,6 +60,12 @@
private static final String DEFAULT_TITLE_FORMAT = "MMMMy";
private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
+ /** Virtual view ID for previous button. */
+ private static final int ITEM_ID_PREV = 0x101;
+
+ /** Virtual view ID for next button. */
+ private static final int ITEM_ID_NEXT = 0x100;
+
private final TextPaint mMonthPaint = new TextPaint();
private final TextPaint mDayOfWeekPaint = new TextPaint();
private final TextPaint mDayPaint = new TextPaint();
@@ -66,27 +73,43 @@
private final Paint mDayHighlightPaint = new Paint();
private final Calendar mCalendar = Calendar.getInstance();
- private final Calendar mDayLabelCalendar = Calendar.getInstance();
+ private final Calendar mDayOfWeekLabelCalendar = Calendar.getInstance();
private final MonthViewTouchHelper mTouchHelper;
private final SimpleDateFormat mTitleFormatter;
private final SimpleDateFormat mDayOfWeekFormatter;
+ // Desired dimensions.
+ private final int mDesiredMonthHeight;
+ private final int mDesiredDayOfWeekHeight;
+ private final int mDesiredDayHeight;
+ private final int mDesiredCellWidth;
+ private final int mDesiredDaySelectorRadius;
+
+ // Next/previous drawables.
+ private final Drawable mPrevDrawable;
+ private final Drawable mNextDrawable;
+ private final Rect mPrevHitArea;
+ private final Rect mNextHitArea;
+ private final CharSequence mPrevContentDesc;
+ private final CharSequence mNextContentDesc;
+
private CharSequence mTitle;
private int mMonth;
private int mYear;
+ // Dimensions as laid out.
+ private int mMonthHeight;
+ private int mDayOfWeekHeight;
+ private int mDayHeight;
+ private int mCellWidth;
+ private int mDaySelectorRadius;
+
private int mPaddedWidth;
private int mPaddedHeight;
- private final int mMonthHeight;
- private final int mDayOfWeekHeight;
- private final int mDayHeight;
- private final int mCellWidth;
- private final int mDaySelectorRadius;
-
/** The day of month for the selected day, or -1 if no day is selected. */
private int mActivatedDay = -1;
@@ -122,7 +145,10 @@
private ColorStateList mDayTextColor;
- private int mTouchedDay = -1;
+ private int mTouchedItem = -1;
+
+ private boolean mPrevEnabled;
+ private boolean mNextEnabled;
public SimpleMonthView(Context context) {
this(context, null);
@@ -140,11 +166,18 @@
super(context, attrs, defStyleAttr, defStyleRes);
final Resources res = context.getResources();
- mMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height);
- mDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
- mDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
- mCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
- mDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
+ mDesiredMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height);
+ mDesiredDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
+ mDesiredDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
+ mDesiredCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
+ mDesiredDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
+
+ mPrevDrawable = context.getDrawable(R.drawable.ic_chevron_left);
+ mNextDrawable = context.getDrawable(R.drawable.ic_chevron_right);
+ mPrevHitArea = mPrevDrawable != null ? new Rect() : null;
+ mNextHitArea = mNextDrawable != null ? new Rect() : null;
+ mPrevContentDesc = res.getText(R.string.date_picker_prev_month_button);
+ mNextContentDesc = res.getText(R.string.date_picker_next_month_button);
// Set up accessibility components.
mTouchHelper = new MonthViewTouchHelper(this);
@@ -160,6 +193,18 @@
initPaints(res);
}
+ public void setNextEnabled(boolean enabled) {
+ mNextEnabled = enabled;
+ mTouchHelper.invalidateRoot();
+ invalidate();
+ }
+
+ public void setPrevEnabled(boolean enabled) {
+ mPrevEnabled = enabled;
+ mTouchHelper.invalidateRoot();
+ invalidate();
+ }
+
/**
* Applies the specified text appearance resource to a paint, returning the
* text color if one is set in the text appearance.
@@ -192,7 +237,16 @@
}
public void setMonthTextAppearance(int resId) {
- applyTextAppearance(mMonthPaint, resId);
+ final ColorStateList monthColor = applyTextAppearance(mMonthPaint, resId);
+ if (monthColor != null) {
+ if (mPrevDrawable != null) {
+ mPrevDrawable.setTintList(monthColor);
+ }
+ if (mNextDrawable != null) {
+ mNextDrawable.setTintList(monthColor);
+ }
+ }
+
invalidate();
}
@@ -300,23 +354,26 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
+ final int x = (int) (event.getX() + 0.5f);
+ final int y = (int) (event.getY() + 0.5f);
+
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
- final int touchedDay = getDayAtLocation(event.getX(), event.getY());
- if (mTouchedDay != touchedDay) {
- mTouchedDay = touchedDay;
+ final int touchedItem = getItemAtLocation(x, y);
+ if (mTouchedItem != touchedItem) {
+ mTouchedItem = touchedItem;
invalidate();
}
break;
case MotionEvent.ACTION_UP:
- final int clickedDay = getDayAtLocation(event.getX(), event.getY());
- onDayClicked(clickedDay);
+ final int clickedItem = getItemAtLocation(x, y);
+ onItemClicked(clickedItem, true);
// Fall through.
case MotionEvent.ACTION_CANCEL:
// Reset touched day on stream end.
- mTouchedDay = -1;
+ mTouchedItem = -1;
invalidate();
break;
}
@@ -332,6 +389,7 @@
drawMonth(canvas);
drawDaysOfWeek(canvas);
drawDays(canvas);
+ drawButtons(canvas);
canvas.translate(-paddingLeft, -paddingTop);
}
@@ -347,34 +405,43 @@
}
private void drawDaysOfWeek(Canvas canvas) {
- final float cellWidthHalf = mPaddedWidth / (DAYS_IN_WEEK * 2);
+ final TextPaint p = mDayOfWeekPaint;
+ final int headerHeight = mMonthHeight;
+ final int rowHeight = mDayOfWeekHeight;
+ final int colWidth = mCellWidth;
- // Vertically centered within the cell height.
- final float lineHeight = mDayOfWeekPaint.ascent() + mDayOfWeekPaint.descent();
- final float y = mMonthHeight + (mDayOfWeekHeight - lineHeight) / 2f;
+ // Text is vertically centered within the day of week height.
+ final float halfLineHeight = (p.ascent() + p.descent()) / 2f;
+ final int rowCenter = headerHeight + rowHeight / 2;
- for (int i = 0; i < DAYS_IN_WEEK; i++) {
- final int calendarDay = (i + mWeekStart) % DAYS_IN_WEEK;
- mDayLabelCalendar.set(Calendar.DAY_OF_WEEK, calendarDay);
-
- final String dayLabel = mDayOfWeekFormatter.format(mDayLabelCalendar.getTime());
- final float x = (2 * i + 1) * cellWidthHalf;
- canvas.drawText(dayLabel, x, y, mDayOfWeekPaint);
+ for (int col = 0; col < DAYS_IN_WEEK; col++) {
+ final int colCenter = colWidth * col + colWidth / 2;
+ final int dayOfWeek = (col + mWeekStart) % DAYS_IN_WEEK;
+ final String label = getDayOfWeekLabel(dayOfWeek);
+ canvas.drawText(label, colCenter, rowCenter - halfLineHeight, p);
}
}
+ private String getDayOfWeekLabel(int dayOfWeek) {
+ mDayOfWeekLabelCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
+ return mDayOfWeekFormatter.format(mDayOfWeekLabelCalendar.getTime());
+ }
+
/**
* Draws the month days.
*/
private void drawDays(Canvas canvas) {
- final int cellWidthHalf = mPaddedWidth / (DAYS_IN_WEEK * 2);
+ final TextPaint p = mDayPaint;
+ final int headerHeight = mMonthHeight + mDayOfWeekHeight;
+ final int rowHeight = mDayHeight;
+ final int colWidth = mCellWidth;
- // Vertically centered within the cell height.
- final float halfLineHeight = (mDayPaint.ascent() + mDayPaint.descent()) / 2;
- float centerY = mMonthHeight + mDayOfWeekHeight + mDayHeight / 2f;
+ // Text is vertically centered within the row height.
+ final float halfLineHeight = (p.ascent() + p.descent()) / 2f;
+ int rowCenter = headerHeight + rowHeight / 2;
- for (int day = 1, j = findDayOffset(); day <= mDaysInMonth; day++) {
- final int x = (2 * j + 1) * cellWidthHalf;
+ for (int day = 1, col = findDayOffset(); day <= mDaysInMonth; day++) {
+ final int colCenter = colWidth * col + colWidth / 2;
int stateMask = 0;
if (day >= mEnabledDayStart && day <= mEnabledDayEnd) {
@@ -386,12 +453,12 @@
stateMask |= StateSet.VIEW_STATE_ACTIVATED;
// Adjust the circle to be centered on the row.
- canvas.drawCircle(x, centerY, mDaySelectorRadius, mDaySelectorPaint);
- } else if (mTouchedDay == day) {
+ canvas.drawCircle(colCenter, rowCenter, mDaySelectorRadius, mDaySelectorPaint);
+ } else if (mTouchedItem == day) {
stateMask |= StateSet.VIEW_STATE_PRESSED;
// Adjust the circle to be centered on the row.
- canvas.drawCircle(x, centerY, mDaySelectorRadius, mDayHighlightPaint);
+ canvas.drawCircle(colCenter, rowCenter, mDaySelectorRadius, mDayHighlightPaint);
}
final boolean isDayToday = mToday == day;
@@ -402,19 +469,29 @@
final int[] stateSet = StateSet.get(stateMask);
dayTextColor = mDayTextColor.getColorForState(stateSet, 0);
}
- mDayPaint.setColor(dayTextColor);
+ p.setColor(dayTextColor);
- canvas.drawText("" + day, x, centerY - halfLineHeight, mDayPaint);
+ canvas.drawText(Integer.toString(day), colCenter, rowCenter - halfLineHeight, p);
- j++;
+ col++;
- if (j == DAYS_IN_WEEK) {
- j = 0;
- centerY += mDayHeight;
+ if (col == DAYS_IN_WEEK) {
+ col = 0;
+ rowCenter += rowHeight;
}
}
}
+ private void drawButtons(Canvas canvas) {
+ if (mPrevEnabled && mPrevDrawable != null) {
+ mPrevDrawable.draw(canvas);
+ }
+
+ if (mNextEnabled && mNextDrawable != null) {
+ mNextDrawable.draw(canvas);
+ }
+ }
+
private static boolean isValidDayOfWeek(int day) {
return day >= Calendar.SUNDAY && day <= Calendar.SATURDAY;
}
@@ -558,9 +635,9 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int preferredHeight = mDayHeight * mNumWeeks + mDayOfWeekHeight + mMonthHeight
- + getPaddingTop() + getPaddingBottom();
- final int preferredWidth = mCellWidth * DAYS_IN_WEEK
+ final int preferredHeight = mDesiredDayHeight * mNumWeeks + mDesiredDayOfWeekHeight
+ + mDesiredMonthHeight + getPaddingTop() + getPaddingBottom();
+ final int preferredWidth = mDesiredCellWidth * DAYS_IN_WEEK
+ getPaddingStart() + getPaddingEnd();
final int resolvedWidth = resolveSize(preferredWidth, widthMeasureSpec);
final int resolvedHeight = resolveSize(preferredHeight, heightMeasureSpec);
@@ -568,9 +645,73 @@
}
@Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- mPaddedWidth = w - getPaddingLeft() - getPaddingRight();
- mPaddedHeight = w - getPaddingTop() - getPaddingBottom();
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (!changed) {
+ return;
+ }
+
+ // Let's initialize a completely reasonable number of variables.
+ final int w = right - left;
+ final int h = bottom - top;
+ final int paddingLeft = getPaddingLeft();
+ final int paddingTop = getPaddingTop();
+ final int paddingRight = getPaddingRight();
+ final int paddingBottom = getPaddingBottom();
+ final int paddedRight = w - paddingRight;
+ final int paddedBottom = h - paddingBottom;
+ final int paddedWidth = paddedRight - paddingLeft;
+ final int paddedHeight = paddedBottom - paddingTop;
+ if (paddedWidth == mPaddedWidth || paddedHeight == mPaddedHeight) {
+ return;
+ }
+
+ mPaddedWidth = paddedWidth;
+ mPaddedHeight = paddedHeight;
+
+ // We may have been laid out smaller than our preferred size. If so,
+ // scale all dimensions to fit.
+ final int measuredPaddedHeight = getMeasuredHeight() - paddingTop - paddingBottom;
+ final float scaleH = paddedHeight / (float) measuredPaddedHeight;
+ final int monthHeight = (int) (mDesiredMonthHeight * scaleH);
+ final int cellWidth = mPaddedWidth / DAYS_IN_WEEK;
+ mMonthHeight = monthHeight;
+ mDayOfWeekHeight = (int) (mDesiredDayOfWeekHeight * scaleH);
+ mDayHeight = (int) (mDesiredDayHeight * scaleH);
+ mCellWidth = cellWidth;
+
+ // Compute the largest day selector radius that's still within the clip
+ // bounds and desired selector radius.
+ final int maxSelectorWidth = cellWidth / 2 + Math.min(paddingLeft, paddingRight);
+ final int maxSelectorHeight = mDayHeight / 2 + paddingBottom;
+ mDaySelectorRadius = Math.min(mDesiredDaySelectorRadius,
+ Math.min(maxSelectorWidth, maxSelectorHeight));
+
+ // Vertically center the previous/next drawables within the month
+ // header, horizontally center within the day cell, then expand the
+ // hit area to ensure it's at least 48x48dp.
+ final Drawable prevDrawable = mPrevDrawable;
+ if (prevDrawable != null) {
+ final int dW = prevDrawable.getIntrinsicWidth();
+ final int dH = prevDrawable.getIntrinsicHeight();
+ final int iconTop = (monthHeight - dH) / 2;
+ final int iconLeft = (cellWidth - dW) / 2;
+
+ // Button bounds don't include padding, but hit area does.
+ prevDrawable.setBounds(iconLeft, iconTop, iconLeft + dW, iconTop + dH);
+ mPrevHitArea.set(0, 0, paddingLeft + cellWidth, paddingTop + monthHeight);
+ }
+
+ final Drawable nextDrawable = mNextDrawable;
+ if (nextDrawable != null) {
+ final int dW = nextDrawable.getIntrinsicWidth();
+ final int dH = nextDrawable.getIntrinsicHeight();
+ final int iconTop = (monthHeight - dH) / 2;
+ final int iconRight = paddedWidth - (cellWidth - dW) / 2;
+
+ // Button bounds don't include padding, but hit area does.
+ nextDrawable.setBounds(iconRight - dW, iconTop, iconRight, iconTop + dH);
+ mNextHitArea.set(paddedRight - cellWidth, 0, w, paddingTop + monthHeight);
+ }
// Invalidate cached accessibility information.
mTouchHelper.invalidateRoot();
@@ -585,22 +726,29 @@
}
/**
- * Calculates the day of the month at the specified touch position. Returns
- * the day of the month or -1 if the position wasn't in a valid day.
+ * Calculates the day of the month or item identifier at the specified
+ * touch position. Returns the day of the month or -1 if the position
+ * wasn't in a valid day.
*
* @param x the x position of the touch event
* @param y the y position of the touch event
- * @return the day of the month at (x, y) or -1 if the position wasn't in a
- * valid day
+ * @return the day of the month at (x, y), an item identifier, or -1 if the
+ * position wasn't in a valid day or item
*/
- private int getDayAtLocation(float x, float y) {
- final int paddedX = (int) (x - getPaddingLeft() + 0.5f);
+ private int getItemAtLocation(int x, int y) {
+ if (mNextEnabled && mNextDrawable != null && mNextHitArea.contains(x, y)) {
+ return ITEM_ID_NEXT;
+ } else if (mPrevEnabled && mPrevDrawable != null && mPrevHitArea.contains(x, y)) {
+ return ITEM_ID_PREV;
+ }
+
+ final int paddedX = x - getPaddingLeft();
if (paddedX < 0 || paddedX >= mPaddedWidth) {
return -1;
}
final int headerHeight = mMonthHeight + mDayOfWeekHeight;
- final int paddedY = (int) (y - getPaddingTop() + 0.5f);
+ final int paddedY = y - getPaddingTop();
if (paddedY < headerHeight || paddedY >= mPaddedHeight) {
return -1;
}
@@ -619,47 +767,97 @@
/**
* Calculates the bounds of the specified day.
*
- * @param day the day of the month
+ * @param id the day of the month, or an item identifier
* @param outBounds the rect to populate with bounds
*/
- private boolean getBoundsForDay(int day, Rect outBounds) {
- if (day < 1 || day > mDaysInMonth) {
+ private boolean getBoundsForItem(int id, Rect outBounds) {
+ if (mNextEnabled && id == ITEM_ID_NEXT) {
+ if (mNextDrawable != null) {
+ outBounds.set(mNextHitArea);
+ return true;
+ }
+ } else if (mPrevEnabled && id == ITEM_ID_PREV) {
+ if (mPrevDrawable != null) {
+ outBounds.set(mPrevHitArea);
+ return true;
+ }
+ }
+
+ if (id < 1 || id > mDaysInMonth) {
return false;
}
- final int index = day - 1 + findDayOffset();
- final int row = index / DAYS_IN_WEEK;
+ final int index = id - 1 + findDayOffset();
+
+ // Compute left edge.
final int col = index % DAYS_IN_WEEK;
+ final int colWidth = mCellWidth;
+ final int left = getPaddingLeft() + col * colWidth;
+ // Compute top edge.
+ final int row = index / DAYS_IN_WEEK;
+ final int rowHeight = mDayHeight;
final int headerHeight = mMonthHeight + mDayOfWeekHeight;
- final int paddedY = row * mDayHeight + headerHeight;
- final int paddedX = col * mPaddedWidth;
+ final int top = getPaddingTop() + headerHeight + row * rowHeight;
- final int y = paddedY + getPaddingTop();
- final int x = paddedX + getPaddingLeft();
-
- final int cellHeight = mDayHeight;
- final int cellWidth = mPaddedWidth / DAYS_IN_WEEK;
- outBounds.set(x, y, (x + cellWidth), (y + cellHeight));
-
+ outBounds.set(left, top, left + colWidth, top + rowHeight);
return true;
}
/**
+ * Called when an item is clicked.
+ *
+ * @param id the day number or item identifier
+ */
+ private boolean onItemClicked(int id, boolean animate) {
+ return onNavigationClicked(id, animate) || onDayClicked(id);
+ }
+
+ /**
* Called when the user clicks on a day. Handles callbacks to the
* {@link OnDayClickListener} if one is set.
*
* @param day the day that was clicked
*/
- private void onDayClicked(int day) {
+ private boolean onDayClicked(int day) {
+ if (day < 0 || day > mDaysInMonth) {
+ return false;
+ }
+
if (mOnDayClickListener != null) {
- Calendar date = Calendar.getInstance();
+ final Calendar date = Calendar.getInstance();
date.set(mYear, mMonth, day);
mOnDayClickListener.onDayClick(this, date);
}
// This is a no-op if accessibility is turned off.
mTouchHelper.sendEventForVirtualView(day, AccessibilityEvent.TYPE_VIEW_CLICKED);
+ return true;
+ }
+
+ /**
+ * Called when the user clicks on a navigation button. Handles callbacks to
+ * the {@link OnDayClickListener} if one is set.
+ *
+ * @param id the item identifier
+ */
+ private boolean onNavigationClicked(int id, boolean animate) {
+ final int direction;
+ if (id == ITEM_ID_NEXT) {
+ direction = 1;
+ } else if (id == ITEM_ID_PREV) {
+ direction = -1;
+ } else {
+ return false;
+ }
+
+ if (mOnDayClickListener != null) {
+ mOnDayClickListener.onNavigationClick(this, direction, animate);
+ }
+
+ // This is a no-op if accessibility is turned off.
+ mTouchHelper.sendEventForVirtualView(id, AccessibilityEvent.TYPE_VIEW_CLICKED);
+ return true;
}
/**
@@ -678,7 +876,7 @@
@Override
protected int getVirtualViewAt(float x, float y) {
- final int day = getDayAtLocation(x, y);
+ final int day = getItemAtLocation((int) (x + 0.5f), (int) (y + 0.5f));
if (day >= 0) {
return day;
}
@@ -687,6 +885,14 @@
@Override
protected void getVisibleVirtualViews(IntArray virtualViewIds) {
+ if (mNextEnabled && mNextDrawable != null) {
+ virtualViewIds.add(ITEM_ID_PREV);
+ }
+
+ if (mPrevEnabled && mPrevDrawable != null) {
+ virtualViewIds.add(ITEM_ID_NEXT);
+ }
+
for (int day = 1; day <= mDaysInMonth; day++) {
virtualViewIds.add(day);
}
@@ -699,7 +905,7 @@
@Override
protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) {
- final boolean hasBounds = getBoundsForDay(virtualViewId, mTempRect);
+ final boolean hasBounds = getBoundsForItem(virtualViewId, mTempRect);
if (!hasBounds) {
// The day is invalid, kill the node.
@@ -710,12 +916,14 @@
return;
}
+ node.setText(getItemText(virtualViewId));
node.setContentDescription(getItemDescription(virtualViewId));
node.setBoundsInParent(mTempRect);
node.addAction(AccessibilityAction.ACTION_CLICK);
if (virtualViewId == mActivatedDay) {
- node.setSelected(true);
+ // TODO: This should use activated once that's supported.
+ node.setChecked(true);
}
}
@@ -725,31 +933,45 @@
Bundle arguments) {
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK:
- onDayClicked(virtualViewId);
- return true;
+ return onItemClicked(virtualViewId, false);
}
return false;
}
/**
- * Generates a description for a given time object. Since this
- * description will be spoken, the components are ordered by descending
- * specificity as DAY MONTH YEAR.
+ * Generates a description for a given virtual view.
*
- * @param day The day to generate a description for
- * @return A description of the time object
+ * @param id the day or item identifier to generate a description for
+ * @return a description of the virtual view
*/
- private CharSequence getItemDescription(int day) {
- mTempCalendar.set(mYear, mMonth, day);
- final CharSequence date = DateFormat.format(DATE_FORMAT,
- mTempCalendar.getTimeInMillis());
-
- if (day == mActivatedDay) {
- return getContext().getString(R.string.item_is_selected, date);
+ private CharSequence getItemDescription(int id) {
+ if (id == ITEM_ID_NEXT) {
+ return mNextContentDesc;
+ } else if (id == ITEM_ID_PREV) {
+ return mPrevContentDesc;
+ } else if (id >= 1 && id <= mDaysInMonth) {
+ mTempCalendar.set(mYear, mMonth, id);
+ return DateFormat.format(DATE_FORMAT, mTempCalendar.getTimeInMillis());
}
- return date;
+ return "";
+ }
+
+ /**
+ * Generates displayed text for a given virtual view.
+ *
+ * @param id the day or item identifier to generate text for
+ * @return the visible text of the virtual view
+ */
+ private CharSequence getItemText(int id) {
+ if (id == ITEM_ID_NEXT || id == ITEM_ID_PREV) {
+ return null;
+ } else if (id >= 1 && id <= mDaysInMonth) {
+ return Integer.toString(id);
+ }
+
+ return null;
}
}
@@ -758,5 +980,6 @@
*/
public interface OnDayClickListener {
public void onDayClick(SimpleMonthView view, Calendar day);
+ public void onNavigationClick(SimpleMonthView view, int direction, boolean animate);
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 718ef93..2723080 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -543,6 +543,8 @@
private float mSpacingMult = 1.0f;
private float mSpacingAdd = 0.0f;
+ private int mBreakStrategy;
+
private int mMaximum = Integer.MAX_VALUE;
private int mMaxMode = LINES;
private int mMinimum = 0;
@@ -680,6 +682,7 @@
boolean elegant = false;
float letterSpacing = 0;
String fontFeatureSettings = null;
+ mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
final Resources.Theme theme = context.getTheme();
@@ -1133,6 +1136,9 @@
case com.android.internal.R.styleable.TextView_fontFeatureSettings:
fontFeatureSettings = a.getString(attr);
break;
+
+ case com.android.internal.R.styleable.TextView_breakStrategy:
+ mBreakStrategy = a.getInt(attr, Layout.BREAK_STRATEGY_SIMPLE);
}
}
a.recycle();
@@ -2960,6 +2966,35 @@
}
/**
+ * Sets the break strategy for breaking paragraphs into lines. The default value for
+ * TextView is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}, and the default value for
+ * EditText is {@link Layout#BREAK_STRATEGY_SIMPLE}, the latter to avoid the
+ * text "dancing" when being edited.
+ *
+ * @attr ref android.R.styleable#TextView_breakStrategy
+ * @see #getBreakStrategy()
+ */
+ public void setBreakStrategy(@Layout.BreakStrategy int breakStrategy) {
+ mBreakStrategy = breakStrategy;
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ /**
+ * @return the currently set break strategy.
+ *
+ * @attr ref android.R.styleable#TextView_breakStrategy
+ * @see #setBreakStrategy(int)
+ */
+ @Layout.BreakStrategy
+ public int getBreakStrategy() {
+ return mBreakStrategy;
+ }
+
+ /**
* Sets font feature settings. The format is the same as the CSS
* font-feature-settings attribute:
* http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
@@ -6492,27 +6527,25 @@
hintBoring, mIncludePad, mEllipsize,
ellipsisWidth);
}
- } else if (shouldEllipsize) {
- mHintLayout = new StaticLayout(mHint,
- 0, mHint.length(),
- mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, mEllipsize,
- ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
- } else {
- mHintLayout = new StaticLayout(mHint, mTextPaint,
- hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
- mIncludePad);
}
- } else if (shouldEllipsize) {
- mHintLayout = new StaticLayout(mHint,
- 0, mHint.length(),
- mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, mEllipsize,
- ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
- } else {
- mHintLayout = new StaticLayout(mHint, mTextPaint,
- hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
- mIncludePad);
+ }
+ // TODO: code duplication with makeSingleLayout()
+ if (mHintLayout == null) {
+ StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0,
+ mHint.length(), hintWidth)
+ .setPaint(mTextPaint)
+ .setAlignment(alignment)
+ .setTextDir(mTextDir)
+ .setSpacingMult(mSpacingMult)
+ .setSpacingAdd(mSpacingAdd)
+ .setIncludePad(mIncludePad)
+ .setBreakStrategy(mBreakStrategy);
+ if (shouldEllipsize) {
+ builder.setEllipsize(mEllipsize)
+ .setEllipsizedWidth(ellipsisWidth)
+ .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+ }
+ mHintLayout = builder.build();
}
}
@@ -6544,9 +6577,8 @@
Layout result = null;
if (mText instanceof Spannable) {
result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
- alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, getKeyListener() == null ? effectiveEllipsize : null,
- ellipsisWidth);
+ alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mBreakStrategy,
+ getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
} else {
if (boring == UNKNOWN_BORING) {
boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
@@ -6583,29 +6615,27 @@
boring, mIncludePad, effectiveEllipsize,
ellipsisWidth);
}
- } else if (shouldEllipsize) {
- result = new StaticLayout(mTransformed,
- 0, mTransformed.length(),
- mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, effectiveEllipsize,
- ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
- } else {
- result = new StaticLayout(mTransformed, mTextPaint,
- wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
- mIncludePad);
}
- } else if (shouldEllipsize) {
- result = new StaticLayout(mTransformed,
- 0, mTransformed.length(),
- mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult,
- mSpacingAdd, mIncludePad, effectiveEllipsize,
- ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
- } else {
- result = new StaticLayout(mTransformed, mTextPaint,
- wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
- mIncludePad);
}
}
+ if (result == null) {
+ StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed,
+ 0, mTransformed.length(), wantWidth)
+ .setPaint(mTextPaint)
+ .setAlignment(alignment)
+ .setTextDir(mTextDir)
+ .setSpacingMult(mSpacingMult)
+ .setSpacingAdd(mSpacingAdd)
+ .setIncludePad(mIncludePad)
+ .setBreakStrategy(mBreakStrategy);
+ if (shouldEllipsize) {
+ builder.setEllipsize(effectiveEllipsize)
+ .setEllipsizedWidth(ellipsisWidth)
+ .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+ }
+ // TODO: explore always setting maxLines
+ result = builder.build();
+ }
return result;
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 944b491..986c0f8 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Widget;
import android.content.Context;
@@ -29,18 +30,13 @@
import java.util.Locale;
/**
- * A view for selecting the time of day, in either 24 hour or AM/PM mode. The
- * hour, each minute digit, and AM/PM (if applicable) can be conrolled by
- * vertical spinners. The hour can be entered by keyboard input. Entering in two
- * digit hours can be accomplished by hitting two digits within a timeout of
- * about a second (e.g. '1' then '2' to select 12). The minutes can be entered
- * by entering single digits. Under AM/PM mode, the user can hit 'a', 'A", 'p'
- * or 'P' to pick. For a dialog using this view, see
- * {@link android.app.TimePickerDialog}.
+ * A widget for selecting the time of day, in either 24-hour or AM/PM mode.
* <p>
- * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
- * guide.
- * </p>
+ * For a dialog using this view, see {@link android.app.TimePickerDialog}. See
+ * the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
+ * guide for more information.
+ *
+ * @attr ref android.R.styleable#TimePicker_timePickerMode
*/
@Widget
public class TimePicker extends FrameLayout {
@@ -96,44 +92,105 @@
}
/**
- * Set the current hour.
+ * Sets the currently selected hour using 24-hour time.
+ *
+ * @param hour the hour to set, in the range (0-23)
+ * @see #getHour()
*/
- public void setCurrentHour(Integer currentHour) {
- mDelegate.setCurrentHour(currentHour);
+ public void setHour(int hour) {
+ mDelegate.setCurrentHour(hour);
}
/**
- * @return The current hour in the range (0-23).
+ * Returns the currently selected hour using 24-hour time.
+ *
+ * @return the currently selected hour, in the range (0-23)
+ * @see #setHour(int)
*/
+ public int getHour() {
+ return mDelegate.getCurrentHour();
+ }
+
+ /**
+ * Sets the currently selected minute..
+ *
+ * @param minute the minute to set, in the range (0-59)
+ * @see #getMinute()
+ */
+ public void setMinute(int minute) {
+ mDelegate.setCurrentMinute(minute);
+ }
+
+ /**
+ * Returns the currently selected minute.
+ *
+ * @return the currently selected minute, in the range (0-59)
+ * @see #setMinute(int)
+ */
+ public int getMinute() {
+ return mDelegate.getCurrentMinute();
+ }
+
+ /**
+ * Sets the current hour.
+ *
+ * @deprecated Use {@link #setHour(int)}
+ */
+ @Deprecated
+ public void setCurrentHour(@NonNull Integer currentHour) {
+ setHour(currentHour);
+ }
+
+ /**
+ * @return the current hour in the range (0-23)
+ * @deprecated Use {@link #getHour()}
+ */
+ @NonNull
+ @Deprecated
public Integer getCurrentHour() {
return mDelegate.getCurrentHour();
}
/**
* Set the current minute (0-59).
+ *
+ * @deprecated Use {@link #setMinute(int)}
*/
- public void setCurrentMinute(Integer currentMinute) {
+ @Deprecated
+ public void setCurrentMinute(@NonNull Integer currentMinute) {
mDelegate.setCurrentMinute(currentMinute);
}
/**
- * @return The current minute.
+ * @return the current minute
+ * @deprecated Use {@link #getMinute()}
*/
+ @NonNull
+ @Deprecated
public Integer getCurrentMinute() {
return mDelegate.getCurrentMinute();
}
/**
- * Set whether in 24 hour or AM/PM mode.
+ * Sets whether this widget displays time in 24-hour mode or 12-hour mode
+ * with an AM/PM picker.
*
- * @param is24HourView True = 24 hour mode. False = AM/PM.
+ * @param is24HourView {@code true} to display in 24-hour mode,
+ * {@code false} for 12-hour mode with AM/PM
+ * @see #is24HourView()
*/
- public void setIs24HourView(Boolean is24HourView) {
+ public void setIs24HourView(@NonNull Boolean is24HourView) {
+ if (is24HourView == null) {
+ return;
+ }
+
mDelegate.setIs24HourView(is24HourView);
}
/**
- * @return true if this is in 24 hour view else false.
+ * @return {@code true} if this widget displays time in 24-hour mode,
+ * {@code false} otherwise}
+ * @see #setIs24HourView(Boolean)
*/
public boolean is24HourView() {
return mDelegate.is24HourView();
@@ -210,13 +267,13 @@
* for the real behavior.
*/
interface TimePickerDelegate {
- void setCurrentHour(Integer currentHour);
- Integer getCurrentHour();
+ void setCurrentHour(int currentHour);
+ int getCurrentHour();
- void setCurrentMinute(Integer currentMinute);
- Integer getCurrentMinute();
+ void setCurrentMinute(int currentMinute);
+ int getCurrentMinute();
- void setIs24HourView(Boolean is24HourView);
+ void setIs24HourView(boolean is24HourView);
boolean is24HourView();
void setOnTimeChangedListener(OnTimeChangedListener onTimeChangedListener);
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 718d216..2365b48 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -25,8 +25,10 @@
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.SpannableStringBuilder;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
+import android.text.style.TtsSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.util.StateSet;
@@ -155,13 +157,16 @@
mHourView.setMinWidth(computeStableWidth(mHourView, 24));
mMinuteView.setMinWidth(computeStableWidth(mMinuteView, 60));
+ final SpannableStringBuilder amLabel = new SpannableStringBuilder()
+ .append(amPmStrings[0], new TtsSpan.VerbatimBuilder(amPmStrings[0]).build(), 0);
+
// Set up AM/PM labels.
mAmPmLayout = mainView.findViewById(R.id.ampm_layout);
mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
- mAmLabel.setText(amPmStrings[0]);
+ mAmLabel.setText(obtainVerbatim(amPmStrings[0]));
mAmLabel.setOnClickListener(mClickListener);
mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label);
- mPmLabel.setText(amPmStrings[1]);
+ mPmLabel.setText(obtainVerbatim(amPmStrings[1]));
mPmLabel.setOnClickListener(mClickListener);
// For the sake of backwards compatibility, attempt to extract the text
@@ -220,6 +225,11 @@
initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
}
+ private static final CharSequence obtainVerbatim(String text) {
+ return new SpannableStringBuilder().append(text,
+ new TtsSpan.VerbatimBuilder(text).build(), 0);
+ }
+
/**
* The legacy text color might have been poorly defined. Ensures that it
* has an appropriate activated state, using the selected state if one
@@ -376,7 +386,7 @@
* Set the current hour.
*/
@Override
- public void setCurrentHour(Integer currentHour) {
+ public void setCurrentHour(int currentHour) {
if (mInitialHourOfDay == currentHour) {
return;
}
@@ -393,7 +403,7 @@
* @return The current hour in the range (0-23).
*/
@Override
- public Integer getCurrentHour() {
+ public int getCurrentHour() {
int currentHour = mRadialTimePickerView.getCurrentHour();
if (mIs24HourView) {
return currentHour;
@@ -412,7 +422,7 @@
* Set the current minute (0-59).
*/
@Override
- public void setCurrentMinute(Integer currentMinute) {
+ public void setCurrentMinute(int currentMinute) {
if (mInitialMinute == currentMinute) {
return;
}
@@ -427,7 +437,7 @@
* @return The current minute.
*/
@Override
- public Integer getCurrentMinute() {
+ public int getCurrentMinute() {
return mRadialTimePickerView.getCurrentMinute();
}
@@ -437,7 +447,7 @@
* @param is24HourView True = 24 hour mode. False = AM/PM.
*/
@Override
- public void setIs24HourView(Boolean is24HourView) {
+ public void setIs24HourView(boolean is24HourView) {
if (is24HourView == mIs24HourView) {
return;
}
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 513c55b..df6b0a9 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -279,13 +279,13 @@
}
@Override
- public void setCurrentHour(Integer currentHour) {
+ public void setCurrentHour(int currentHour) {
setCurrentHour(currentHour, true);
}
- private void setCurrentHour(Integer currentHour, boolean notifyTimeChanged) {
+ private void setCurrentHour(int currentHour, boolean notifyTimeChanged) {
// why was Integer used in the first place?
- if (currentHour == null || currentHour == getCurrentHour()) {
+ if (currentHour == getCurrentHour()) {
return;
}
if (!is24HourView()) {
@@ -310,7 +310,7 @@
}
@Override
- public Integer getCurrentHour() {
+ public int getCurrentHour() {
int currentHour = mHourSpinner.getValue();
if (is24HourView()) {
return currentHour;
@@ -322,7 +322,7 @@
}
@Override
- public void setCurrentMinute(Integer currentMinute) {
+ public void setCurrentMinute(int currentMinute) {
if (currentMinute == getCurrentMinute()) {
return;
}
@@ -331,12 +331,12 @@
}
@Override
- public Integer getCurrentMinute() {
+ public int getCurrentMinute() {
return mMinuteSpinner.getValue();
}
@Override
- public void setIs24HourView(Boolean is24HourView) {
+ public void setIs24HourView(boolean is24HourView) {
if (mIs24HourView == is24HourView) {
return;
}
diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java
index 7bd502e..7182414 100644
--- a/core/java/android/widget/YearPickerView.java
+++ b/core/java/android/widget/YearPickerView.java
@@ -111,16 +111,12 @@
mAdapter.setRange(min, max);
}
- public void setYearTextAppearance(int resId) {
- mAdapter.setItemTextAppearance(resId);
- }
-
- public void setYearActivatedTextAppearance(int resId) {
- mAdapter.setItemActivatedTextAppearance(resId);
- }
-
private static class YearAdapter extends BaseAdapter {
private static final int ITEM_LAYOUT = R.layout.year_label_text_view;
+ private static final int ITEM_TEXT_APPEARANCE =
+ R.style.TextAppearance_Material_DatePicker_List_YearLabel;
+ private static final int ITEM_TEXT_ACTIVATED_APPEARANCE =
+ R.style.TextAppearance_Material_DatePicker_List_YearLabel_Activated;
private final LayoutInflater mInflater;
@@ -128,9 +124,6 @@
private int mMinYear;
private int mCount;
- private int mItemTextAppearanceResId;
- private int mItemActivatedTextAppearanceResId;
-
public YearAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@@ -155,16 +148,6 @@
return false;
}
- public void setItemTextAppearance(int resId) {
- mItemTextAppearanceResId = resId;
- notifyDataSetChanged();
- }
-
- public void setItemActivatedTextAppearance(int resId) {
- mItemActivatedTextAppearanceResId = resId;
- notifyDataSetChanged();
- }
-
@Override
public int getCount() {
return mCount;
@@ -203,10 +186,10 @@
final boolean activated = mActivatedYear == year;
final int textAppearanceResId;
- if (activated && mItemActivatedTextAppearanceResId != 0) {
- textAppearanceResId = mItemActivatedTextAppearanceResId;
+ if (activated && ITEM_TEXT_ACTIVATED_APPEARANCE != 0) {
+ textAppearanceResId = ITEM_TEXT_ACTIVATED_APPEARANCE;
} else {
- textAppearanceResId = mItemTextAppearanceResId;
+ textAppearanceResId = ITEM_TEXT_APPEARANCE;
}
final TextView v = (TextView) convertView;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 3ceea9d..6b35f3f 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -604,9 +604,10 @@
if ((mAlwaysUseOption || mAdapter.hasFilteredItem()) && mAdapter.mOrigResolveList != null) {
// Build a reasonable intent filter, based on what matched.
IntentFilter filter = new IntentFilter();
+ String action = intent.getAction();
- if (intent.getAction() != null) {
- filter.addAction(intent.getAction());
+ if (action != null) {
+ filter.addAction(action);
}
Set<String> categories = intent.getCategories();
if (categories != null) {
@@ -688,8 +689,30 @@
if (r.match > bestMatch) bestMatch = r.match;
}
if (alwaysCheck) {
- getPackageManager().addPreferredActivity(filter, bestMatch, set,
- intent.getComponent());
+ PackageManager pm = getPackageManager();
+
+ // Set the preferred Activity
+ pm.addPreferredActivity(filter, bestMatch, set, intent.getComponent());
+
+ // Update Domain Verification status
+ int userId = getUserId();
+ ComponentName cn = intent.getComponent();
+ String packageName = cn.getPackageName();
+ String dataScheme = (data != null) ? data.getScheme() : null;
+
+ boolean isHttpOrHttps = (dataScheme != null) &&
+ (dataScheme.equals(IntentFilter.SCHEME_HTTP) ||
+ dataScheme.equals(IntentFilter.SCHEME_HTTPS));
+
+ boolean isViewAction = (action != null) && action.equals(Intent.ACTION_VIEW);
+ boolean hasCategoryBrowsable = (categories != null) &&
+ categories.contains(Intent.CATEGORY_BROWSABLE);
+
+ if (isHttpOrHttps && isViewAction && hasCategoryBrowsable) {
+ pm.updateIntentVerificationStatus(packageName,
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
+ userId);
+ }
} else {
try {
AppGlobals.getPackageManager().setLastChosenActivity(intent,
diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags
index 9e178df..870d20d 100644
--- a/core/java/com/android/internal/logging/EventLogTags.logtags
+++ b/core/java/com/android/internal/logging/EventLogTags.logtags
@@ -4,4 +4,4 @@
# interaction logs
524287 sysui_view_visibility (category|1|5),(visible|1|6)
-524288 sysui_action (category|1|5),(type|1|6)
+524288 sysui_action (category|1|5)
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 2de7394..9b45e34 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -31,6 +31,15 @@
public static final int MANAGE_APPLICATIONS_ALL = 134;
public static final int MANAGE_APPLICATIONS_NOTIFICATIONS = 135;
+ public static final int ACTION_WIFI_ADD_NETWORK = 136;
+ public static final int ACTION_WIFI_CONNECT = 137;
+ public static final int ACTION_WIFI_FORCE_SCAN = 138;
+ public static final int ACTION_WIFI_FORGET = 139;
+ public static final int ACTION_WIFI_OFF = 140;
+ public static final int ACTION_WIFI_ON = 141;
+
+ public static final int MANAGE_PERMISSIONS = 142;
+
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
throw new IllegalArgumentException("Must define metric category");
@@ -44,4 +53,11 @@
}
EventLogTags.writeSysuiViewVisibility(category, 0);
}
+
+ public static void action(Context context, int category) {
+ if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
+ throw new IllegalArgumentException("Must define metric category");
+ }
+ EventLogTags.writeSysuiAction(category);
+ }
}
diff --git a/core/java/com/android/internal/midi/EventScheduler.java b/core/java/com/android/internal/midi/EventScheduler.java
index 7526609..7b9a48c 100644
--- a/core/java/com/android/internal/midi/EventScheduler.java
+++ b/core/java/com/android/internal/midi/EventScheduler.java
@@ -27,10 +27,11 @@
public class EventScheduler {
private static final long NANOS_PER_MILLI = 1000000;
- private final Object lock = new Object();
+ private final Object mLock = new Object();
private SortedMap<Long, FastEventQueue> mEventBuffer;
private FastEventQueue mEventPool = null;
private int mMaxPoolSize = 200;
+ private boolean mClosed;
public EventScheduler() {
mEventBuffer = new TreeMap<Long, FastEventQueue>();
@@ -146,7 +147,7 @@
* @param event
*/
public void add(SchedulableEvent event) {
- synchronized (lock) {
+ synchronized (mLock) {
FastEventQueue list = mEventBuffer.get(event.getTimestamp());
if (list == null) {
long lowestTime = mEventBuffer.isEmpty() ? Long.MAX_VALUE
@@ -156,7 +157,7 @@
// If the event we added is earlier than the previous earliest
// event then notify any threads waiting for the next event.
if (event.getTimestamp() < lowestTime) {
- lock.notify();
+ mLock.notify();
}
} else {
list.add(event);
@@ -183,7 +184,7 @@
*/
public SchedulableEvent getNextEvent(long time) {
SchedulableEvent event = null;
- synchronized (lock) {
+ synchronized (mLock) {
if (!mEventBuffer.isEmpty()) {
long lowestTime = mEventBuffer.firstKey();
// Is it time for this list to be processed?
@@ -206,9 +207,9 @@
*/
public SchedulableEvent waitNextEvent() throws InterruptedException {
SchedulableEvent event = null;
- while (true) {
- long millisToWait = Integer.MAX_VALUE;
- synchronized (lock) {
+ synchronized (mLock) {
+ while (!mClosed) {
+ long millisToWait = Integer.MAX_VALUE;
if (!mEventBuffer.isEmpty()) {
long now = System.nanoTime();
long lowestTime = mEventBuffer.firstKey();
@@ -228,9 +229,16 @@
}
}
}
- lock.wait((int) millisToWait);
+ mLock.wait((int) millisToWait);
}
}
return event;
}
+
+ public void close() {
+ synchronized (mLock) {
+ mClosed = true;
+ mLock.notify();
+ }
+ }
}
diff --git a/core/java/com/android/internal/midi/MidiEventScheduler.java b/core/java/com/android/internal/midi/MidiEventScheduler.java
index 3a1d3fc..42d70f6 100644
--- a/core/java/com/android/internal/midi/MidiEventScheduler.java
+++ b/core/java/com/android/internal/midi/MidiEventScheduler.java
@@ -28,10 +28,16 @@
// Maintain a pool of scheduled events to reduce memory allocation.
// This pool increases performance by about 14%.
private final static int POOL_EVENT_SIZE = 16;
- private MidiReceiver mReceiver = new SchedulingReceiver();
- private class SchedulingReceiver extends MidiReceiver
- {
+ private final MidiReceiver[] mReceivers;
+
+ private class SchedulingReceiver extends MidiReceiver {
+ private final int mPortNumber;
+
+ public SchedulingReceiver(int portNumber) {
+ mPortNumber = portNumber;
+ }
+
/**
* Store these bytes in the EventScheduler to be delivered at the specified
* time.
@@ -41,12 +47,14 @@
throws IOException {
MidiEvent event = createScheduledEvent(msg, offset, count, timestamp);
if (event != null) {
+ event.portNumber = mPortNumber;
add(event);
}
}
}
public static class MidiEvent extends SchedulableEvent {
+ public int portNumber;
public int count = 0;
public byte[] data;
@@ -72,6 +80,17 @@
}
}
+ public MidiEventScheduler() {
+ this(0);
+ }
+
+ public MidiEventScheduler(int portCount) {
+ mReceivers = new MidiReceiver[portCount];
+ for (int i = 0; i < portCount; i++) {
+ mReceivers[i] = new SchedulingReceiver(i);
+ }
+ }
+
/**
* Create an event that contains the message.
*/
@@ -113,7 +132,15 @@
* @return the MidiReceiver
*/
public MidiReceiver getReceiver() {
- return mReceiver;
+ return mReceivers[0];
+ }
+
+ /**
+ * This MidiReceiver will write date to the scheduling buffer.
+ * @return the MidiReceiver
+ */
+ public MidiReceiver getReceiver(int portNumber) {
+ return mReceivers[portNumber];
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 93dc995..05ed3ab 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -104,7 +104,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 122 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 123 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 8674a21..75b6446 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -41,15 +41,10 @@
/** enable the JIT compiler */
public static final int DEBUG_ENABLE_JIT = 1 << 5;
-
/** No external storage should be mounted. */
public static final int MOUNT_EXTERNAL_NONE = 0;
- /** Single-user external storage should be mounted. */
- public static final int MOUNT_EXTERNAL_SINGLEUSER = 1;
- /** Multi-user external storage should be mounted. */
- public static final int MOUNT_EXTERNAL_MULTIUSER = 2;
- /** All multi-user external storage should be mounted. */
- public static final int MOUNT_EXTERNAL_MULTIUSER_ALL = 3;
+ /** Default user-specific external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_DEFAULT = 1;
private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 4d405b2..9106ccd 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -514,10 +514,8 @@
"Duplicate arg specified");
}
niceName = arg.substring(arg.indexOf('=') + 1);
- } else if (arg.equals("--mount-external-multiuser")) {
- mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
- } else if (arg.equals("--mount-external-multiuser-all")) {
- mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
+ } else if (arg.equals("--mount-external-default")) {
+ mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
} else if (arg.equals("--query-abi-list")) {
abiListQuery = true;
} else if (arg.startsWith("--instruction-set=")) {
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index 8018942..8d66191 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -42,6 +42,7 @@
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityRecord;
import android.view.animation.Interpolator;
import android.widget.EdgeEffect;
@@ -371,8 +372,6 @@
mCloseEnough = (int) (CLOSE_ENOUGH * density);
mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density);
- setAccessibilityDelegate(new MyAccessibilityDelegate());
-
if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}
@@ -2695,29 +2694,6 @@
}
@Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- // Dispatch scroll events from this ViewPager.
- if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
- return super.dispatchPopulateAccessibilityEvent(event);
- }
-
- // Dispatch all other accessibility events from the current page.
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- if (child.getVisibility() == VISIBLE) {
- final ItemInfo ii = infoForChild(child);
- if (ii != null && ii.position == mCurItem &&
- child.dispatchPopulateAccessibilityEvent(event)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- @Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams();
}
@@ -2737,60 +2713,63 @@
return new LayoutParams(getContext(), attrs);
}
- class MyAccessibilityDelegate extends AccessibilityDelegate {
- @Override
- public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(host, event);
- event.setClassName(ViewPager.class.getName());
- final AccessibilityRecord record = AccessibilityRecord.obtain();
- record.setScrollable(canScroll());
- if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED
- && mAdapter != null) {
- record.setItemCount(mAdapter.getCount());
- record.setFromIndex(mCurItem);
- record.setToIndex(mCurItem);
- }
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+
+ event.setClassName(ViewPager.class.getName());
+ event.setScrollable(canScroll());
+
+ if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED && mAdapter != null) {
+ event.setItemCount(mAdapter.getCount());
+ event.setFromIndex(mCurItem);
+ event.setToIndex(mCurItem);
+ }
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+
+ info.setClassName(ViewPager.class.getName());
+ info.setScrollable(canScroll());
+
+ if (canScrollHorizontally(1)) {
+ info.addAction(AccessibilityAction.ACTION_SCROLL_FORWARD);
}
- @Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- info.setClassName(ViewPager.class.getName());
- info.setScrollable(canScroll());
- if (canScrollHorizontally(1)) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
- }
- if (canScrollHorizontally(-1)) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
- }
+ if (canScrollHorizontally(-1)) {
+ info.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD);
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle args) {
+ if (super.performAccessibilityAction(action, args)) {
+ return true;
}
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (super.performAccessibilityAction(host, action, args)) {
- return true;
- }
- switch (action) {
- case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
- if (canScrollHorizontally(1)) {
- setCurrentItem(mCurItem + 1);
- return true;
- }
- } return false;
- case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
- if (canScrollHorizontally(-1)) {
- setCurrentItem(mCurItem - 1);
- return true;
- }
- } return false;
- }
- return false;
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
+ if (canScrollHorizontally(1)) {
+ setCurrentItem(mCurItem + 1);
+ return true;
+ }
+ return false;
+ case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
+ if (canScrollHorizontally(-1)) {
+ setCurrentItem(mCurItem - 1);
+ return true;
+ }
+ return false;
}
- private boolean canScroll() {
- return (mAdapter != null) && (mAdapter.getCount() > 1);
- }
+ return false;
+ }
+
+ private boolean canScroll() {
+ return mAdapter != null && mAdapter.getCount() > 1;
}
private class PagerObserver extends DataSetObserver {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 34de6c5..f1b04a5 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -552,12 +552,15 @@
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
+ char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];
char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
+ char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
+ char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
char extraOptsBuf[PROPERTY_VALUE_MAX];
@@ -733,6 +736,9 @@
parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
"--compiler-filter=", "-Xcompiler-option");
}
+ parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option");
+ parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j",
+ "-Ximage-compiler-option");
property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
@@ -824,6 +830,10 @@
snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
addOption(cpuAbiListBuf);
+ // Dalvik-cache pruning counter.
+ parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
+ "-Xzygote-max-boot-retry=");
+
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 49ee6c5..4c08b4b 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -89,7 +89,7 @@
static void restore(JNIEnv* env, jobject, jlong canvasHandle) {
Canvas* canvas = get_canvas(canvasHandle);
if (canvas->getSaveCount() <= 1) { // cannot restore anymore
- // fail silently on underflow, so as not to break existing apps that miscount
+ doThrowISE(env, "Underflow in restore - more restores than saves");
return;
}
canvas->restore();
@@ -98,7 +98,7 @@
static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount) {
Canvas* canvas = get_canvas(canvasHandle);
if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
- // fail silently on underflow, so as not to break existing apps that miscount
+ doThrowIAE(env, "Underflow in restoreToCount - more restores than saves");
return;
}
canvas->restoreToCount(restoreCount);
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 4a98f27..fc05a6d 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -142,7 +142,14 @@
static const char* const kEventHandlerClassPathName =
"android/media/AudioPortEventHandler";
-static jmethodID gPostEventFromNative;
+static struct {
+ jfieldID mJniCallback;
+} gEventHandlerFields;
+static struct {
+ jmethodID postEventFromNative;
+} gAudioPortEventHandlerMethods;
+
+static Mutex gLock;
enum AudioError {
kAudioStatusOk = 0,
@@ -173,14 +180,14 @@
private:
void sendEvent(int event);
- jclass mClass; // Reference to AudioPortEventHandlerDelegate class
- jobject mObject; // Weak ref to AudioPortEventHandlerDelegate Java object to call on
+ jclass mClass; // Reference to AudioPortEventHandler class
+ jobject mObject; // Weak ref to AudioPortEventHandler Java object to call on
};
JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
{
- // Hold onto the SoundTriggerModule class for use in calling the static method
+ // Hold onto the AudioPortEventHandler class for use in calling the static method
// that posts events to the application thread.
jclass clazz = env->GetObjectClass(thiz);
if (clazz == NULL) {
@@ -189,7 +196,7 @@
}
mClass = (jclass)env->NewGlobalRef(clazz);
- // We use a weak reference so the SoundTriggerModule object can be garbage collected.
+ // We use a weak reference so the AudioPortEventHandler object can be garbage collected.
// The reference is only used as a proxy for callbacks.
mObject = env->NewGlobalRef(weak_thiz);
}
@@ -211,7 +218,7 @@
if (env == NULL) {
return;
}
- env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
+ env->CallStaticVoidMethod(mClass, gAudioPortEventHandlerMethods.postEventFromNative, mObject,
event, 0, 0, NULL);
if (env->ExceptionCheck()) {
ALOGW("An exception occurred while notifying an event.");
@@ -234,6 +241,23 @@
sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
}
+static sp<JNIAudioPortCallback> setJniCallback(JNIEnv* env,
+ jobject thiz,
+ const sp<JNIAudioPortCallback>& callback)
+{
+ Mutex::Autolock l(gLock);
+ sp<JNIAudioPortCallback> old =
+ (JNIAudioPortCallback*)env->GetLongField(thiz, gEventHandlerFields.mJniCallback);
+ if (callback.get()) {
+ callback->incStrong((void*)setJniCallback);
+ }
+ if (old != 0) {
+ old->decStrong((void*)setJniCallback);
+ }
+ env->SetLongField(thiz, gEventHandlerFields.mJniCallback, (jlong)callback.get());
+ return old;
+}
+
static int check_AudioSystem_Command(status_t status)
{
switch (status) {
@@ -1355,7 +1379,9 @@
sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
- AudioSystem::setAudioPortCallback(callback);
+ if (AudioSystem::addAudioPortCallback(callback) == NO_ERROR) {
+ setJniCallback(env, thiz, callback);
+ }
}
static void
@@ -1363,9 +1389,11 @@
{
ALOGV("eventHandlerFinalize");
- sp<JNIAudioPortCallback> callback;
+ sp<JNIAudioPortCallback> callback = setJniCallback(env, thiz, 0);
- AudioSystem::setAudioPortCallback(callback);
+ if (callback != 0) {
+ AudioSystem::removeAudioPortCallback(callback);
+ }
}
static jint
@@ -1636,9 +1664,11 @@
"Landroid/media/AudioHandle;");
jclass eventHandlerClass = FindClassOrDie(env, kEventHandlerClassPathName);
- gPostEventFromNative = GetStaticMethodIDOrDie(env, eventHandlerClass, "postEventFromNative",
- "(Ljava/lang/Object;IIILjava/lang/Object;)V");
-
+ gAudioPortEventHandlerMethods.postEventFromNative = GetStaticMethodIDOrDie(
+ env, eventHandlerClass, "postEventFromNative",
+ "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+ gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
+ eventHandlerClass, "mJniCallback", "J");
jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 6cc1f68..87c58d6 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -21,6 +21,7 @@
#include "unicode/brkiter.h"
#include "utils/misc.h"
#include "utils/Log.h"
+#include "ScopedStringChars.h"
#include "ScopedPrimitiveArray.h"
#include "JNIHelp.h"
#include "core_jni_helpers.h"
@@ -47,11 +48,6 @@
static jclass gLineBreaks_class;
static JLineBreaksID gLineBreaks_fieldID;
-static const int CHAR_SPACE = 0x20;
-static const int CHAR_TAB = 0x09;
-static const int CHAR_NEWLINE = 0x0a;
-static const int CHAR_ZWSP = 0x200b;
-
// set text and set a number of parameters for creating a layout (width, tabstops, strategy)
static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length,
jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
@@ -71,14 +67,14 @@
}
static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
- jfloatArray recycleWidths, jbooleanArray recycleFlags,
+ jfloatArray recycleWidths, jintArray recycleFlags,
jint recycleLength, size_t nBreaks, const jint* breaks,
- const jfloat* widths, const jboolean* flags) {
+ const jfloat* widths, const jint* flags) {
if ((size_t)recycleLength < nBreaks) {
// have to reallocate buffers
recycleBreaks = env->NewIntArray(nBreaks);
recycleWidths = env->NewFloatArray(nBreaks);
- recycleFlags = env->NewBooleanArray(nBreaks);
+ recycleFlags = env->NewIntArray(nBreaks);
env->SetObjectField(recycle, gLineBreaks_fieldID.breaks, recycleBreaks);
env->SetObjectField(recycle, gLineBreaks_fieldID.widths, recycleWidths);
@@ -87,12 +83,12 @@
// copy data
env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, breaks);
env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, widths);
- env->SetBooleanArrayRegion(recycleFlags, 0, nBreaks, flags);
+ env->SetIntArrayRegion(recycleFlags, 0, nBreaks, flags);
}
static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
jobject recycle, jintArray recycleBreaks,
- jfloatArray recycleWidths, jbooleanArray recycleFlags,
+ jfloatArray recycleWidths, jintArray recycleFlags,
jint recycleLength) {
LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
@@ -119,12 +115,20 @@
b->finish();
}
-static void nSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName) {
+static jlong nLoadHyphenator(JNIEnv* env, jclass, jstring patternData) {
+ ScopedStringChars str(env, patternData);
+ Hyphenator* hyphenator = Hyphenator::load(str.get(), str.size());
+ return reinterpret_cast<jlong>(hyphenator);
+}
+
+static void nSetLocale(JNIEnv* env, jclass, jlong nativePtr, jstring javaLocaleName,
+ jlong nativeHyphenator) {
ScopedIcuLocale icuLocale(env, javaLocaleName);
LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
+ Hyphenator* hyphenator = reinterpret_cast<Hyphenator*>(nativeHyphenator);
if (icuLocale.valid()) {
- b->setLocale(icuLocale.locale());
+ b->setLocale(icuLocale.locale(), hyphenator);
}
}
@@ -164,13 +168,14 @@
{"nNewBuilder", "()J", (void*) nNewBuilder},
{"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
{"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
- {"nSetLocale", "(JLjava/lang/String;)V", (void*) nSetLocale},
+ {"nLoadHyphenator", "(Ljava/lang/String;)J", (void*) nLoadHyphenator},
+ {"nSetLocale", "(JLjava/lang/String;J)V", (void*) nSetLocale},
{"nSetupParagraph", "(J[CIFIF[III)V", (void*) nSetupParagraph},
{"nAddStyleRun", "(JJJIIZ)F", (void*) nAddStyleRun},
{"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun},
{"nAddReplacementRun", "(JIIF)V", (void*) nAddReplacementRun},
{"nGetWidths", "(J[F)V", (void*) nGetWidths},
- {"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[ZI)I",
+ {"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[II)I",
(void*) nComputeLineBreaks}
};
@@ -181,7 +186,7 @@
gLineBreaks_fieldID.breaks = GetFieldIDOrDie(env, gLineBreaks_class, "breaks", "[I");
gLineBreaks_fieldID.widths = GetFieldIDOrDie(env, gLineBreaks_class, "widths", "[F");
- gLineBreaks_fieldID.flags = GetFieldIDOrDie(env, gLineBreaks_class, "flags", "[Z");
+ gLineBreaks_fieldID.flags = GetFieldIDOrDie(env, gLineBreaks_class, "flags", "[I");
return RegisterMethodsOrDie(env, "android/text/StaticLayout", gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index fff8604..f1c90ea 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -192,6 +192,9 @@
case HAL_PIXEL_FORMAT_YCbCr_422_I:
// Name differs, though the value is the same
return PublicFormat::YUY2;
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ // Name differs, though the value is the same
+ return PublicFormat::PRIVATE;
case HAL_PIXEL_FORMAT_Y16:
// Dataspace-dependent
switch (dataSpace) {
@@ -216,7 +219,6 @@
break;
case HAL_PIXEL_FORMAT_BGRA_8888:
case HAL_PIXEL_FORMAT_RAW_OPAQUE:
- case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
// Not defined in public API
return PublicFormat::UNKNOWN;
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 3d9a9ed..11b3805 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -21,6 +21,7 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
+#include <ScopedPrimitiveArray.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -35,6 +36,7 @@
#include <Animator.h>
#include <AnimationContext.h>
#include <IContextFactory.h>
+#include <JankTracker.h>
#include <RenderNode.h>
#include <renderthread/CanvasContext.h>
#include <renderthread/RenderProxy.h>
@@ -219,6 +221,12 @@
proxy->setTextureAtlas(buffer, map, len);
}
+static void android_view_ThreadedRenderer_setProcessStatsBuffer(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jint fd) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setProcessStatsBuffer(fd);
+}
+
static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
RootRenderNode* node = new RootRenderNode(env);
node->incStrong(0);
@@ -403,6 +411,16 @@
proxy->dumpProfileInfo(fd, dumpFlags);
}
+static void android_view_ThreadedRenderer_dumpProfileData(JNIEnv* env, jobject clazz,
+ jbyteArray jdata, jobject javaFileDescriptor) {
+ int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
+ ScopedByteArrayRO buffer(env, jdata);
+ if (buffer.get()) {
+ JankTracker::dumpBuffer(buffer.get(), buffer.size(), fd);
+ }
+}
+
+
// ----------------------------------------------------------------------------
// Shaders
// ----------------------------------------------------------------------------
@@ -423,6 +441,7 @@
static JNINativeMethod gMethods[] = {
{ "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V", (void*) android_view_ThreadedRenderer_setAtlas },
+ { "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
{ "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
{ "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
{ "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
@@ -449,6 +468,7 @@
{ "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
{ "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
{ "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
+ { "nDumpProfileData", "([BLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileData },
{ "setupShadersDiskCache", "(Ljava/lang/String;)V",
(void*) android_view_ThreadedRenderer_setupShadersDiskCache },
};
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 2bfeadb..76db5d3 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -65,9 +65,7 @@
// Must match values in com.android.internal.os.Zygote.
enum MountExternalKind {
MOUNT_EXTERNAL_NONE = 0,
- MOUNT_EXTERNAL_SINGLEUSER = 1,
- MOUNT_EXTERNAL_MULTIUSER = 2,
- MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
+ MOUNT_EXTERNAL_DEFAULT = 1,
};
static void RuntimeAbort(JNIEnv* env) {
@@ -269,57 +267,16 @@
// See storage config details at http://source.android.com/tech/storage/
userid_t user_id = multiuser_get_user_id(uid);
- // Create bind mounts to expose external storage
- if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
- // These paths must already be created by init.rc
- const char* source = getenv("EMULATED_STORAGE_SOURCE");
- const char* target = getenv("EMULATED_STORAGE_TARGET");
- const char* legacy = getenv("EXTERNAL_STORAGE");
- if (source == NULL || target == NULL || legacy == NULL) {
- ALOGW("Storage environment undefined; unable to provide external storage");
- return false;
- }
+ // Bind mount user-specific storage into place
+ const String8 source(String8::format("/mnt/user/%d", user_id));
+ const String8 target(String8::format("/storage/self"));
- // Prepare source paths
+ if (fs_prepare_dir(source.string(), 0755, 0, 0) == -1) {
+ return false;
+ }
- // /mnt/shell/emulated/0
- const String8 source_user(String8::format("%s/%d", source, user_id));
- // /storage/emulated/0
- const String8 target_user(String8::format("%s/%d", target, user_id));
-
- if (fs_prepare_dir(source_user.string(), 0000, 0, 0) == -1
- || fs_prepare_dir(target_user.string(), 0000, 0, 0) == -1) {
- return false;
- }
-
- if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
- // Mount entire external storage tree for all users
- if (TEMP_FAILURE_RETRY(mount(source, target, NULL, MS_BIND, NULL)) == -1) {
- ALOGW("Failed to mount %s to %s: %s", source, target, strerror(errno));
- return false;
- }
- } else {
- // Only mount user-specific external storage
- if (TEMP_FAILURE_RETRY(mount(source_user.string(), target_user.string(), NULL,
- MS_BIND, NULL)) == -1) {
- ALOGW("Failed to mount %s to %s: %s", source_user.string(), target_user.string(),
- strerror(errno));
- return false;
- }
- }
-
- if (fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
- return false;
- }
-
- // Finally, mount user-specific path into place for legacy users
- if (TEMP_FAILURE_RETRY(
- mount(target_user.string(), legacy, NULL, MS_BIND | MS_REC, NULL)) == -1) {
- ALOGW("Failed to mount %s to %s: %s", target_user.string(), legacy, strerror(errno));
- return false;
- }
- } else {
- ALOGW("Mount mode %d unsupported", mount_mode);
+ if (TEMP_FAILURE_RETRY(mount(source.string(), target.string(), NULL, MS_BIND, NULL)) == -1) {
+ ALOGW("Failed to mount %s to %s: %s", source.string(), target.string(), strerror(errno));
return false;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 851c4bf..b0771dd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -73,6 +73,7 @@
<protected-broadcast android:name="android.intent.action.USER_BACKGROUND" />
<protected-broadcast android:name="android.intent.action.USER_FOREGROUND" />
<protected-broadcast android:name="android.intent.action.USER_SWITCHED" />
+ <protected-broadcast android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
<protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
@@ -1220,6 +1221,14 @@
android:label="@string/permlab_cameraDisableTransmitLed"
android:description="@string/permdesc_cameraDisableTransmitLed" />
+ <!-- Allows sending the camera service notifications about system-wide events.
+ @hide -->
+ <permission android:name="android.permission.CAMERA_SEND_SYSTEM_EVENTS"
+ android:permissionGroup="android.permission-group.CAMERA"
+ android:protectionLevel="signature|system"
+ android:label="@string/permdesc_cameraSendSystemEvent"
+ android:description="@string/permdesc_cameraSendSystemEvent" />
+
<!-- =========================================== -->
<!-- Permissions associated with telephony state -->
<!-- =========================================== -->
@@ -2592,6 +2601,12 @@
android:description="@string/permdesc_performCdmaProvisioning"
android:protectionLevel="signature|system" />
+ <!-- @SystemApi Allows an application to perform SIM Activation @hide -->
+ <permission android:name="android.permission.PERFORM_SIM_ACTIVATION"
+ android:label="@string/permlab_performSimActivation"
+ android:description="@string/permdesc_performSimActivation"
+ android:protectionLevel="signature|system" />
+
<!-- @SystemApi Allows enabling/disabling location update notifications from
the radio.
<p>Not for use by third-party applications. -->
@@ -2799,6 +2814,23 @@
android:description="@string/permdesc_bindPackageVerifier"
android:protectionLevel="signature" />
+ <!-- @SystemApi @hide Intent filter verifier needs to have this permission before the
+ PackageManager will trust it to verify intent filters.
+ -->
+ <permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"
+ android:label="@string/permlab_intentFilterVerificationAgent"
+ android:description="@string/permdesc_intentFilterVerificationAgent"
+ android:protectionLevel="signature|system" />
+
+ <!-- Must be required by intent filter verifier receiver, to ensure that only the
+ system can interact with it.
+ @hide
+ -->
+ <permission android:name="android.permission.BIND_INTENT_FILTER_VERIFIER"
+ android:label="@string/permlab_bindIntentFilterVerifier"
+ android:description="@string/permdesc_bindIntentFilterVerifier"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows applications to access serial ports via the SerialManager.
@hide -->
<permission android:name="android.permission.SERIAL_PORT"
@@ -3161,9 +3193,9 @@
</intent-filter>
</receiver>
- <receiver android:name="com.android.server.updates.TZInfoInstallReceiver" >
+ <receiver android:name="com.android.server.updates.TzDataInstallReceiver" >
<intent-filter>
- <action android:name="android.intent.action.UPDATE_TZINFO" />
+ <action android:name="android.intent.action.UPDATE_TZDATA" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
diff --git a/core/res/res/color/date_picker_header_text_material.xml b/core/res/res/color/date_picker_header_text_material.xml
deleted file mode 100644
index baa8958..0000000
--- a/core/res/res/color/date_picker_header_text_material.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_activated="true"
- android:color="?attr/textColorPrimaryInverse" />
- <item
- android:color="?attr/textColorSecondaryInverse" />
-</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_chevron_left.xml b/core/res/res/drawable/ic_chevron_left.xml
new file mode 100644
index 0000000..dc24706
--- /dev/null
+++ b/core/res/res/drawable/ic_chevron_left.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M15.41 7.41L14 6l-6 6 6 6 1.41,-1.41L10.83 12z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_chevron_right.xml b/core/res/res/drawable/ic_chevron_right.xml
new file mode 100644
index 0000000..4e6d8e3
--- /dev/null
+++ b/core/res/res/drawable/ic_chevron_right.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6,-6z"/>
+</vector>
diff --git a/core/res/res/layout/date_picker_month_item_material.xml b/core/res/res/layout/date_picker_month_item_material.xml
new file mode 100644
index 0000000..cb79cee
--- /dev/null
+++ b/core/res/res/layout/date_picker_month_item_material.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<android.widget.SimpleMonthView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/month_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/day_picker_padding_horizontal"
+ android:paddingEnd="@dimen/day_picker_padding_horizontal"
+ android:paddingTop="@dimen/day_picker_padding_top" />
diff --git a/core/res/res/layout/date_picker_view_animator_material.xml b/core/res/res/layout/date_picker_view_animator_material.xml
index 98ef1dd..620ddfa 100644
--- a/core/res/res/layout/date_picker_view_animator_material.xml
+++ b/core/res/res/layout/date_picker_view_animator_material.xml
@@ -26,9 +26,8 @@
android:id="@+id/date_picker_day_picker"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingStart="@dimen/day_picker_padding_horizontal"
- android:paddingEnd="@dimen/day_picker_padding_horizontal"
- android:paddingTop="@dimen/day_picker_padding_top" />
+ android:inAnimation="@anim/fade_in"
+ android:outAnimation="@anim/fade_out" />
<android.widget.YearPickerView
android:id="@+id/date_picker_year_picker"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 44db8cc..2bc6849 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Laat die program toe om foto\'s en video\'s met die kamera te neem. Hierdie toestemming laat die program toe om die kamera te eniger tyd sonder jou bevestiging te gebruik."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"deaktiveer LED wat oordrag aandui wanneer kamera gebruik word"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Laat \'n pre-geïnstalleerde stelselprogram toe om die LED wat kamera-gebruik aandui, te deaktiveer."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"deaktiveer tablet permanent"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"deaktiveer TV permanent"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"deaktiveer foon permanent"</string>
@@ -757,7 +759,7 @@
</string-array>
<string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"Kon nie verwerk nie. Probeer weer."</string>
<string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"Hardeware is nie beskikbaar nie."</string>
- <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan nie geberg word nie. Verwyder asseblief \'n bestaande vingerafdruk."</string>
+ <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan nie gestoor word nie. Verwyder asseblief \'n bestaande vingerafdruk."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vingerafdrukuittelling is bereik. Probeer weer."</string>
<string name="fingerprint_error_vendor" msgid="3175724710791609491">"Vingerafdrukuittelling is bereik. Probeer weer."</string>
<string-array name="fingerprint_error_vendor">
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Laat die program toe om te verifieer dat \'n pakket installeerbaar is."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind aan \'n pakkieverifieerder"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Laat die houer toe om versoeke aan pakketverifieerders te rig. Dit moet nooit vir normale programme nodig wees nie."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifieer voornemefilter"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Laat die program toe om te kyk of \'n voornemefilter geverifieer is of nie."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bind aan \'n voornemefilterverifieerder"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Laat die houer toe om versoeke te rig aan voornemefilterverifieerders. Behoort nooit vir normale programme nodig te wees nie."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"kry toegang tot reekspoorte"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Laat die houer toe om toegang te verkry tot reekspoorte wat die SerialManager API gebruik."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"verkry toegang tot inhoud ekstern"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Verminder dag"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Vermeerder jaar"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Verminder jaar"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Vorige maand"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Volgende maand"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Kanselleer"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Vee uit"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Kies minute"</string>
<string name="select_day" msgid="7774759604701773332">"Kies maand en dag"</string>
<string name="select_year" msgid="7952052866994196170">"Kies jaar"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> gekies"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> uitgevee"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Om hierdie skerm te ontspeld, raak en hou tegelyk Terug en Oorsig."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index be3a864..ba0223d 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"መተግበሪያው በካሜራው ፎቶዎችንና ቪዲዮዎችን እንዲያነሳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ካሜራውን በማንኛውም ጊዜ ያላንተ ማረጋገጫ እንዲጠቀም ይፈቅድለታል።"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ካሜራው ስራ ላይ ሲሆን የማስተላለፍ አመልካች ኤል ኢ ዲን ያሰናክሉ"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ቀድሞ የተጫነ የስርዓት መተግበሪያ ካሜራውን አመላካች ኤል ኢ ዲ እንዳይጠቀም እንዲያሰናክል ያስችለዋል።"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"በቋሚነት ጡባዊ አቦዝን"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"ቴሌቪዥን እስከመጨረሻ አሰናክል"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"በቋሚነት ስልኩን አቦዝን"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ፓኬጅ መጫን የሚችል መሆኑን ለማረጋገጥ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"በፓኬጅ አረጋጋጭ የተወሰነ"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"የፓኬጅ አረጋጋጮችን ጥየቃ ለማድረግ ያዡ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"የፍላጎት ማጣሪያን አረጋግጥ"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"የፍላጎት ማጣሪያው የተረጋገጠ ወይም ያልተረጋገጠ መሆኑን ለመፈተሽ እንዲችል መተግበሪያውን ይፈቅድለታል።"</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"በፍላጎት ማጣሪያ አረጋገጭ ተገደብ"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"የፍላጎት ማጣሪያ አረጋጋጮችን ጥየቃ ለማድረግ ያዡ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
<string name="permlab_serialPort" msgid="546083327654631076">"ተከታታይ ወደቦችን ድረስ"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API. የተከታታይ አደራጅ APIን በመጠቀም ያዡ የተከታታይ ወደቦችን እንዲደርስ ይፈቅዳል።"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ይዘት አቅራቢዎችን በውጭ በኩል ድረስባቸው"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ቀን ቀንስ"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"ዓመት ጨምር"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ዓመት ቀንስ"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ያለፈው ወር"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"ቀጣይ ወር"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ይቅር"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ሰርዝ"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"ደቂቃዎችን ይምረጡ"</string>
<string name="select_day" msgid="7774759604701773332">"ወር እና ቀን ይምረጡ"</string>
<string name="select_year" msgid="7952052866994196170">"ዓመት ይምረጡ"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ተመርጧል"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ተሰርዟል"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"ይህን ማያ ገጽ ለመንቀል ተመለስን እና አጠቃላይ እይታን በተመሳሳይ ይንኳቸውና ይያዟቸው።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index a451930..b8ac523 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -589,6 +589,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"للسماح للتطبيق بالتقاط صور ومقاطع فيديو من خلال الكاميرا. ويتيح هذا الإذن للتطبيق استخدام الكاميرا في أي وقت وبدون موافقة منك."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"تعطيل مؤشر LED للإرسال عندما تكون الكاميرا قيد الاستخدام"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"للسماح لتطبيق نظام مثبت مسبقًا لتعطيل مؤشر LED لاستخدام الكاميرا."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"تعطيل الجهاز اللوحي نهائيًا"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"تعطيل التلفزيون نهائيًا"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"تعطيل الهاتف على الدوام"</string>
@@ -1140,6 +1142,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"السماح للتطبيق بالتحقق من إمكانية تثبيت حزمة."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"الالتزام بمحقق حزمة"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"السماح للمالك بإجراء طلبات محققي الحزمة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"التحقق من فلتر الأهداف"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"للسماح للتطبيق بفحص ما إذا كان فلتر الأهداف قد تم التحقق منه أم لا."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"الالتزام بمحقق فلتر الأهداف"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"للسماح للمالك بإجراء طلبات محققي فلتر الأهداف. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"الدخول إلى المنافذ التسلسلية"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"يسمح لحامله بالدخول إلى المنافذ التسلسلية باستخدام واجهة برمجة التطبيقات."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"الدخول إلى مزودي المحتوى خارجيًا"</string>
@@ -1593,6 +1599,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"تقليل الأيام"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"زيادة الأعوام"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"تقليل الأعوام"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"الشهر السابق"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"الشهر التالي"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"إلغاء"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"حذف"</string>
@@ -1849,7 +1857,6 @@
<string name="select_minutes" msgid="3974345615920336087">"تحديد الدقائق"</string>
<string name="select_day" msgid="7774759604701773332">"تحديد الشهر واليوم"</string>
<string name="select_year" msgid="7952052866994196170">"تحديد العام"</string>
- <string name="item_is_selected" msgid="949687401682476608">"تم تحديد <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"تم حذف <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> المخصص للعمل"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"لإلغاء تثبيت هذه الشاشة، يمكنك لمس \"رجوع\" و\"نظرة عامة\" في آن واحد مع الاستمرار."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index fa5b464..4efbea5 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Разрешава на приложението да прави снимки и видеоклипове с камерата. Това разрешение му позволява да я използва по всяко време без потвърждение от ваша страна."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"деактивиране на светодиодния индикатор за предаване, когато камерата се използва"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Разрешава на предварително инсталирано системно приложение да деактивира светодиодния индикатор за използване на камерата."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"деактивиране на таблета за постоянно"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"деактивиране на телевизора за постоянно"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"деактивиране на телефона за постоянно"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Разрешава на приложението да провери дали пакетът може да се инсталира."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обвързване с верификатор на пакета"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Разрешава на притежателя да прави заявки за верификатори на пакета. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"достъп до серийни портове"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Разрешава на притежателя достъп до серийни портове посредством приложния програмен интерфейс (API) SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"външен достъп до доставчиците на съдърж."</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Намаляване на дните"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Увеличаване на годините"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Намаляване на годините"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Отказ"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Изтриване"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Избиране на минути"</string>
<string name="select_day" msgid="7774759604701773332">"Избиране на месец и ден"</string>
<string name="select_year" msgid="7952052866994196170">"Избиране на година"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Избрахте <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Изтрихте <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> за работа"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"За да освободите екрана, докоснете и задръжте едновременно бутона за връщане назад и този за общ преглед."</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index b29768d..dd383ae 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ক্যামেরার সাহায্যে ছবি তুলতে ও ভিডিও তৈরি করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এই অনুমতিটি অ্যাপ্লিকেশানটিকে আপনার নিশ্চয়তা ছাড়াই যেকোনো সময় ক্যামেরা ব্যবহার করতে মঞ্জুর করে৷"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"যখন ক্যামেরা ব্যবহারে থাকে তখন ট্রান্সমিট সূচক LED অক্ষম করে"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"আগে থেকে ইনস্টল থাকা একটি সিস্টেম অ্যাপ্লিকেশানকে ক্যামেরা ব্যবহারের সূচক LEDটিকে অক্ষম করার অনুমতি দেয়৷"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ট্যাবলেটকে স্থায়ীভাবে অক্ষম করে"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"টিভি স্থায়ীভাবে অক্ষম করে"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ফোনকে স্থায়ীভাবে অক্ষম করে"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"অ্যাপ্লিকেশানকে ইনস্টলযোগ্য প্যাকেজ যাচাই করার অনুমতি দেয়৷"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"একটি প্যাকেজ যাচাইকারীতে সংলগ্ন করে"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ধারককে, প্যাকেজ যাচাইকারীতে অনুরোধগুলি পাঠাতে দেয়৷ সাধারণ অ্যাপ্লিকেশানগুলির জন্য কখনোই প্রয়োজনীয় নয়৷"</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"অভিপ্রায় ফিল্টার যাচাই করুন"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"কোনো অভিপ্রায় ফিল্টার যাচাই করা হয়েছে কি না অ্যাপ্লিকেশানটিকে তা পরীক্ষা করার মঞ্জুরি দেয়৷"</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"একটি অভিপ্রায় ফিল্টার যাচাইকারী আবদ্ধ করুন"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ধারককে,অভিপ্রায় ফিল্টার যাচাইকারীতে অনুরোধগুলি পাঠাতে দেয়৷ সাধারণ অ্যাপ্লিকেশানগুলির জন্য কখনোই প্রয়োজনীয় নয়৷"</string>
<string name="permlab_serialPort" msgid="546083327654631076">"সিরিয়াল পোর্টগুলি অ্যাক্সেস করে"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"সিরিয়াল ম্যানেজার API ব্যবহার করে ধারককে সিরিয়াল পোর্টগুলি অ্যাক্সেস করতে অনুমতি দেয়৷"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"বাহ্যিকভাবে সামগ্রীর পরিষেবা প্রদানকারীদের অ্যাক্সেস করুন"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"দিন কম করুন"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"বছর বাড়ান"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"বছর কম করুন"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"পূর্ববর্তী মাস"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"পরের মাস"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"বাতিল করুন"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"মুছুন"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"মিনিট নির্বাচন করুন"</string>
<string name="select_day" msgid="7774759604701773332">"মাস এবং দিন নির্বাচন করুন"</string>
<string name="select_year" msgid="7952052866994196170">"বছর নির্বাচন করুন"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> নির্বাচন করা হয়েছে"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> মুছে ফেলা হয়েছে"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"কর্মক্ষেত্র <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"এই স্ক্রীনটিকে আনপিন করতে, \'ফিরুন\' এবং \'এক নজরে\' একসাথে স্পর্শ করুন এবং ধরে রাখুন৷"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 6a0066a..e6293d1 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permet que l\'aplicació faci fotos i vídeos amb la càmera. Aquest permís permet que l\'aplicació utilitzi la càmera en qualsevol moment sense la teva confirmació."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desactiva la transmissió del LED indicador en fer servir la càmera"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permet que una aplicació dels sistema preinstal·lada desactivi el LED indicador d\'ús de la càmera."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactiva la tauleta de manera permanent"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"desactivar el televisor de manera permanent"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar definitivament el telèfon"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet que l\'aplicació verifiqui si un paquet es pot instal·lar."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincula a un verificador de paquets"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet que el titular sol·liciti verificadors de paquets. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"accedeix a ports sèrie"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permet que el titular accedeixi a ports sèrie amb l\'API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accedeix als proveïdors de contingut externament"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Fes disminuir el dia"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Fes augmentar l\'any"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Fes disminuir l\'any"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel·la"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Suprimeix"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Selecciona els minuts"</string>
<string name="select_day" msgid="7774759604701773332">"Selecciona un mes i un dia"</string>
<string name="select_year" msgid="7952052866994196170">"Selecciona un any"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionat"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> suprimit"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Per anul·lar la fixació d\'aquesta pantalla, mantén premudes les opcions Enrere i Visió general alhora."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 7429bfc..95f1e90 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -587,6 +587,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikaci pořizovat fotografie a videa pomocí fotoaparátu. Toto oprávnění umožňuje aplikaci používat fotoaparát kdykoliv i bez vašeho svolení."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"vypnutí indikátoru LED přenosu při použití fotoaparátu"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Umožňuje předinstalované systémové aplikaci vypnout kontrolku LED fotoaparátu."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trvalé vypnutí tabletu"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"trvalé vypnutí televize"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"trvalé vypnutí telefonu"</string>
@@ -1138,6 +1140,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikaci ověřit, zda balíček lze nainstalovat."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"navázat na ověřovatele balíčků"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteli podávat žádosti o ověření balíčků. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ověření filtru objektů intent"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Umožňuje aplikaci zkontrolovat, zda je filtr objektů intent ověřený."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"vazba na ověření filtru objektů intent"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Umožňuje držiteli podávat žádosti o ověření filtrů objektů intent. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"přístup k sériovým portům"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Umožňuje držiteli přístup k sériovým portům pomocí rozhraní SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"externí přístup k poskytovatelům obsahu"</string>
@@ -1577,6 +1583,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Ubrat den"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Přidat rok"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Ubrat rok"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Předchozí měsíc"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Příští měsíc"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Zrušit"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Smazat"</string>
@@ -1831,7 +1839,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Zvolte minuty"</string>
<string name="select_day" msgid="7774759604701773332">"Vyberte měsíc a den"</string>
<string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Vybrána položka <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Číslice <xliff:g id="KEY">%1$s</xliff:g> byla smazána"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Pracovní <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Chcete-li tuto obrazovku uvolnit, klepněte současně na možnosti Zpět a Přehled a podržte je."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b6014ef..e93c5ef 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Tillader, at appen kan tage billeder og videoer med kameraet. Med denne tilladelse kan appen til enhver tid bruge kameraet uden din bekræftelse."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"deaktiver sendelysdioden, når kameraet er i brug"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Tillader, at en forudinstalleret systemapplikation deaktiverer lysdioden for brug af kameraet."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"deaktiver tabletcomputeren permanent"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"deaktivere tv\'et permanent"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"deaktiver telefonen permanent"</string>
@@ -925,7 +927,7 @@
<string name="phoneTypeCar" msgid="8738360689616716982">"Bil"</string>
<string name="phoneTypeCompanyMain" msgid="540434356461478916">"Virksomhed (hovednummer)"</string>
<string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
- <string name="phoneTypeMain" msgid="6766137010628326916">"Hoved"</string>
+ <string name="phoneTypeMain" msgid="6766137010628326916">"Hovednr."</string>
<string name="phoneTypeOtherFax" msgid="8587657145072446565">"Andre faxbeskeder"</string>
<string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
<string name="phoneTypeTelex" msgid="3367879952476250512">"Telex"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillader, at appen kan bekræfte, at en pakke kan installeres."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en bekræftelse af pakker"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillader, at indehaveren kan sende anmodninger om bekræftelser af pakker. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"adgang til serielle porte"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Tillader, at indehaveren kan få adgang til serielle porte ved hjælp af SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"adgang til indholdsleverandører eksternt"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Tidligere dag"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Senere år"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Tidligere år"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuller"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Slet"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Vælg minutter"</string>
<string name="select_day" msgid="7774759604701773332">"Vælg måned og dag"</string>
<string name="select_year" msgid="7952052866994196170">"Vælg år"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> er valgt"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> er slettet"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> – arbejde"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Tilbage og Oversigt på samme tid og holde fingeren nede."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 0db7fea..b573c0c 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ermöglicht der App, Bilder und Videos mit der Kamera aufzunehmen. Die Berechtigung erlaubt der App, die Kamera jederzeit und ohne Ihre Bestätigung zu nutzen."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"LED-Anzeige für Übertragung bei Kameranutzung deaktivieren"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Vorinstallierte System-Apps können die LED-Anzeige für die Kameranutzung deaktivieren."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"Tablet dauerhaft deaktivieren"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"Fernseher dauerhaft deaktivieren"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"Telefon dauerhaft deaktivieren"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ermöglicht der App die Überprüfung, ob ein Paket installiert werden kann"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"An Paketprüfung binden"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ermöglicht dem Halter, Anfragen für die Paketprüfung zu senden. Sollte nie für normale Apps benötigt werden."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"Intent-Filter verifizieren"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Ermöglicht einer App, zu überprüfen, ob ein Intent-Filter verifiziert wurde"</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"An Intent-Filter-Verifizierung binden"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Ermöglicht dem Inhaber, Anfragen für die Verifizierung von Intent-Filtern zu senden. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"Zugriff auf serielle Schnittstellen"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Ermöglicht dem Inhaber den Zugriff auf serielle Schnittstellen über das SerialManager-API"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"Extern auf Content-Anbieter zugreifen"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Tag verringern"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Jahr verlängern"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Jahr verringern"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Vormonat"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Nächster Monat"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Abbrechen"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Löschen"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Minuten auswählen"</string>
<string name="select_day" msgid="7774759604701773332">"Monat und Tag auswählen"</string>
<string name="select_year" msgid="7952052866994196170">"Jahr auswählen"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ausgewählt"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> gelöscht"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie gleichzeitig \"Zurück\" und \"Übersicht\"."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 8a9e9d3..bef52de 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Επιτρέπει στην εφαρμογή τη λήψη φωτογραφιών και βίντεο με τη φωτογραφική μηχανή. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να χρησιμοποιεί τη φωτογραφική μηχανή ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"απενεργοποίηση ένδειξης LED μετάδοσης όταν χρησιμοποιείται η φωτογραφική μηχανή"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Επιτρέπει σε μια προεγκατεστημένη εφαρμογή συστήματος να απενεργοποιήσει την ένδειξη LED χρήσης της φωτογραφικής μηχανής."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"μόνιμη απενεργοποίηση του tablet"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"μόνιμη απενεργοποίηση της τηλεόρασης"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"μόνιμη απενεργοποίηση τηλεφώνου"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Επιτρέπει στην εφαρμογή να επαληθεύσει τη δυνατότητα εγκατάστασης ενός πακέτου."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"δέσμευση με επαλήθευση πακέτου"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Επιτρέπει στον κάτοχο να υποβάλλει ερωτήματα σε προγράμματα επαλήθευσης πακέτου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"επαλήθευση φίλτρου πρόθεσης"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Επιτρέπει στην εφαρμογή να ελέγχει εάν ένα φίλτρο πρόθεσης είναι επαληθευμένο ή όχι."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"σύνδεση σε προγρ.επαλήθ.φίλτρου πρόθεσης"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Επιτρέπει στον κάτοχο να υποβάλλει ερωτήματα σε προγράμματα επαλήθευσης φίλτρων πρόθεσης. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"πρόσβαση στις σειριακές θύρες"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Επιτρέπει στον κάτοχο την πρόσβαση στις σειριακές θύρες με τη χρήση του SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"εξωτερική πρόσβαση σε παρόχους περιεχ."</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Μείωση ημέρας"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Αύξηση έτους"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Μείωση έτους"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Προηγούμενος μήνας"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Επόμενος μήνας"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ακύρωση"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Διαγραφή"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Επιλογή λεπτών"</string>
<string name="select_day" msgid="7774759604701773332">"Επιλογή μήνα και ημέρας"</string>
<string name="select_year" msgid="7952052866994196170">"Επιλογή έτους"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Επιλέχτηκε το στοιχείο <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> διαγράφηκε"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Εργασία <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, πατήστε παρατεταμένα \"Επιστροφή\" και \"Επισκόπηση\" ταυτόχρονα."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 389b584..e1386a0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"disable transmit indicator LED when camera is in use"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Allows a pre-installed system application to disable the camera use indicator LED."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"permanently disable tablet"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"permanently disable TV"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"permanently disable phone"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Allows the app to verify a package is installable."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind to a package verifier"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verify intent filter"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Allows the app to check if an intent filter is verified or not."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bind to an intent filter verifier"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Allows the holder to make requests of intent filter verifiers. Should never be needed for normal apps."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"access content providers externally"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Decrease day"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Increase year"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Decrease year"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Previous month"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Next month"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Select minutes"</string>
<string name="select_day" msgid="7774759604701773332">"Select month and day"</string>
<string name="select_year" msgid="7952052866994196170">"Select year"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selected"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 389b584..e1386a0 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"disable transmit indicator LED when camera is in use"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Allows a pre-installed system application to disable the camera use indicator LED."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"permanently disable tablet"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"permanently disable TV"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"permanently disable phone"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Allows the app to verify a package is installable."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind to a package verifier"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verify intent filter"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Allows the app to check if an intent filter is verified or not."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bind to an intent filter verifier"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Allows the holder to make requests of intent filter verifiers. Should never be needed for normal apps."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"access content providers externally"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Decrease day"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Increase year"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Decrease year"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Previous month"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Next month"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Select minutes"</string>
<string name="select_day" msgid="7774759604701773332">"Select month and day"</string>
<string name="select_year" msgid="7952052866994196170">"Select year"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selected"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 389b584..e1386a0 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"disable transmit indicator LED when camera is in use"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Allows a pre-installed system application to disable the camera use indicator LED."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"permanently disable tablet"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"permanently disable TV"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"permanently disable phone"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Allows the app to verify a package is installable."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind to a package verifier"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verify intent filter"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Allows the app to check if an intent filter is verified or not."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bind to an intent filter verifier"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Allows the holder to make requests of intent filter verifiers. Should never be needed for normal apps."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"access content providers externally"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Decrease day"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Increase year"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Decrease year"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Previous month"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Next month"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Select minutes"</string>
<string name="select_day" msgid="7774759604701773332">"Select month and day"</string>
<string name="select_year" msgid="7952052866994196170">"Select year"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selected"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 642ab92..13fd0cf 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación saque fotos o grabe videos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Inhabilitar el indicador LED de transmisión mientras se utiliza la cámara"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que una aplicación del sistema instalada previamente inhabilite el indicador LED de uso de la cámara."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactivar tablet de forma permanente"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"inhabilitar la TV permanentemente"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar dispositivo de manera permanente"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Vincular a un verificador de paquetes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que el titular solicite verificadores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificar filtro de intento"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite que la aplicación compruebe si se verificó un filtro de intento."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"vincular a verificador filtro de intento"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite que el titular solicite verificadores de filtros de intentos. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"Acceder a los puertos serie"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de la API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"acceder a proveedores externamente"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reducir día"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar año"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reducir año"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mes anterior"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mes siguiente"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Seleccionar minutos"</string>
<string name="select_day" msgid="7774759604701773332">"Seleccionar mes y día"</string>
<string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionado"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> borrado"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Para dejar de fijar esta pantalla, mantén presionados los botones para volver y Recientes al mismo tiempo."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 8e1c37b..89cf984 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación haga fotos o grabe vídeos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"inhabilitar el indicador LED de transmisión mientras se utiliza la cámara"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que una aplicación de sistema instalada previamente inhabilite el indicador LED que advierte del uso de la cámara."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"inhabilitar tablet de forma permanente"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"inhabilitar permanentemente la TV"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"inhabilitar el teléfono de forma permanente"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"enlazar con un detector de paquetes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que se envíen solicitudes de detectores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificar filtro de intento"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite que la aplicación compruebe si un filtro de intento se ha verificado."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"enlazar con detector filtro de intento"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite que se envíen solicitudes de detectores de filtros de intentos. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"acceder a puertos serie"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"acceder a proveedores de contenido externamente"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reducir días"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar año"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reducir año"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mes anterior"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Próximo mes"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Seleccionar minutos"</string>
<string name="select_day" msgid="7774759604701773332">"Seleccionar mes y día"</string>
<string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionado"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Para desactivar esta pantalla, mantén pulsados los botones de retroceso y Visión general al mismo tiempo."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 10f1a45..63ff865 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Võimaldab rakendusel teha kaameraga pilte ja videoid. See luba võimaldab rakendusel kasutada kaamerat mis tahes ajal teie kinnituseta."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"keela kaamera kasutamisel näidikutule kasutamine"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Lubab eelinstallitud süsteemirakendusel keelata kaamera näidikutule kasutamise."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"blokeeri tahvelarvuti jäädavalt"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"teleri alaline keelamine"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"blokeeri telefon jäädavalt"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Võimaldab rakendusel kinnitada, et paketti saab installida."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sidumine paketi kinnitajaga"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lubab omanikul teha taotlusi paketi kinnitajate kohta. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"juurdepääs jadaportidele"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Võimaldab omanikul SerialManageri API-liidese abil jadaportidele juurde pääseda."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"väline juurdepääs sisupakkujatele"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Päeva vähendamine"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aasta suurendamine"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Aasta vähendamine"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Tühista"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Kustuta"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Minutite valimine"</string>
<string name="select_day" msgid="7774759604701773332">"Kuu ja päeva valimine"</string>
<string name="select_year" msgid="7952052866994196170">"Aasta valimine"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> on valitud"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> on kustutatud"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Ekraanikuva vabastamiseks puudutage pikalt samal ajal nuppe Tagasi ja Ülevaade."</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index e6ade17..386df35d 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Kamerarekin argazkiak ateratzeko eta bideoak grabatzeko baimena ematen die aplikazioei. Baimen horrekin, aplikazioak kamera edonoiz erabil dezake zure baimenik gabe."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Desgaitu LED argi adierazlea kamera abian denean"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Kamera erabiltzen ari dela adierazten duen LED argia desgaitzeko aukera ematen dio sisteman aurrez instalatutako aplikazio bati."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desgaitu telefonoa behin betiko"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"Desgaitu telebista betiko"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"desgaitu telefonoa behin betiko"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Paketeak instala daitezkeen egiaztatzea baimentzen die aplikazioei."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"lotu pakete-egiaztatzaile batekin"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pakete-egiaztatzaileei eskaerak egitea baimentzen die aplikazioei. Aplikazio normalek ez lukete beharko."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"Egiaztatu saiakera-iragazkia"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Saiakera-iragazki bat egiaztatuta dagoen ala ez egiaztatzea baimentzen die aplikazioei."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"Lotu saiakera-iragazkien egiaztatzaile bati"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Saiakera-iragazkien egiaztatzaileei eskaerak egitea baimentzen die aplikazioei. Aplikazio normalek ez lukete beharko."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"atzitu serie-atakak"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Jabeari serieko atakak atzitzeko aukera ematen dio SerialManager APIa erabilita."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"eduki-hornitzaileak kanpotik atzitzea"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Atzeratu egun bat"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aurreratu urtebete"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Atzeratu urtebete"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Aurreko hilabetea"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Hurrengo hilabetea"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Utzi"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ezabatu"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Hautatu minutuak"</string>
<string name="select_day" msgid="7774759604701773332">"Hautatu hilabetea eta eguna"</string>
<string name="select_year" msgid="7952052866994196170">"Hautatu urtea"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> hautatu da"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ezabatu da"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Laneko <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Aingura kentzeko, eduki ukituta Atzera eta Ikuspegi orokorra botoiak aldi berean."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index babe1f0..ea762f4 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"به برنامه اجازه میدهد با دوربین به عکسبرداری و فیلمبرداری بپردازد. این مجوز به برنامه اجازه میدهد از دوربین در هر زمانی بدون تأیید شما استفاده کند."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"LED نشانگر انتقال داده، هنگام استفاده از دوربین غیرفعال شود"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"به یک برنامه سیستم از قبل نصب شده اجازه میدهد LED نشانگر استفاده از دوربین را غیرفعال کند."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"غیر فعال کردن دائم رایانهٔ لوحی"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"غیرفعالسازی دائم تلویزیون"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"تلفن بطور دائمی غیرفعال شود"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"به برنامه اجازه میدهد قابل نصب بودن بسته را تأیید کند."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"اتصال به یک تأیید کننده بسته"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"به دارنده اجازه میدهد تا تاییدکنندگان بسته را درخواست کند. برای برنامههای عادی نیاز نیست."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"تأیید فیلتر هدف"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"به برنامه اجازه میدهد بررسی کند که فیلتر هدف تأیید شده یا خیر."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ارتباط با یک بررسیکننده فیلتر هدف"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"به دارنده اجازه میدهد بررسیکننده فیلتر هدف را درخواست کند. هرگز نباید برای برنامههای عادی مورد نیاز شود."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"دسترسی به درگاههای سریال"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"به دارنده اجازه میدهد با استفاده از SerialManager API به درگاههای سریال دسترسی داشته باشد."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"دسترسی خارجی به ارائهدهندگان محتوا"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"کاهش روز"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"افزایش سال"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"کاهش سال"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ماه قبل"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"ماه بعد"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"لغو"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"انتخاب دقیقه"</string>
<string name="select_day" msgid="7774759604701773332">"انتخاب ماه و روز"</string>
<string name="select_year" msgid="7952052866994196170">"انتخاب سال"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> انتخاب شد"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> حذف شد"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> محل کار"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"برای برداشتن پین این صفحه، همزمان «بازگشت» و «نمای کلی» را لمس کنید و نگه دارید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 76d3ba4..b66766c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Antaa sovelluksen ottaa kuvia ja kuvata videoita kameralla. Sovellus voi käyttää kameraa milloin tahansa ilman lupaasi."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"poista lähetyksen merkkivalo käytöstä, kun kameraa käytetään"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Antaa valmiiksi asennetun järjestelmäsovelluksen poistaa käytöstä kameran käytössäolon merkkivalon."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"poista tabletti käytöstä lopullisesti"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"Poista televisio pysyvästi käytöstä"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"poista puhelin käytöstä pysyvästi"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Antaa sovelluksen vahvistaa, että pakkaus on asennettavissa."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sitoudu paketin vahvistajaan"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Antaa sovelluksen tehdä pakettien vahvistuspyyntöjä. Ei tavallisten sovellusten käyttöön."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"käytä sarjaportteja"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Luvan haltija voi käyttää sarjaportteja SerialManager-sovellusliittymän avulla."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"käytä ulkoisia sisällöntarjoajia"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Vähennä päivien määrää."</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Lisää vuosien määrää."</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Vähennä vuosien määrää."</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Peruuta"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Poista"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Valitse minuutit"</string>
<string name="select_day" msgid="7774759604701773332">"Valitse kuukausi ja päivä"</string>
<string name="select_year" msgid="7952052866994196170">"Valitse vuosi"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> on valittu"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> poistettiin"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (työ)"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Poista näytön kiinnitys painamalla Edellinen- ja Viimeisimmät-kohtaa samanaikaisesti pitkään."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 81bd0653..f89ed5a 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"désactiver l\'indicateur d\'émission LED lorsque la caméra est en cours d\'utilisation"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permet à une application système préinstallée de désactiver l\'indicateur LED d\'utilisation de la caméra."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"désactiver définitivement la tablette"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"désactiver définitivement le téléviseur"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"désactiver définitivement le téléphone"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet à l\'application de vérifier qu\'un paquet peut être installé."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"s\'associer à un vérificateur de paquet"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de paquet. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"vérifier le filtre d\'intention"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permet à l\'application de vérifier si un filtre d\'intention est validé ou non."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"s\'associer à un vérificateur de filtre d\'intention"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de filtres d\'intention. Les applications standards ne devraient jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"accéder aux ports série"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permet à l\'application autorisée d\'accéder aux ports série avec l\'API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accès externe aux fournisseurs de contenu"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Jour précédent"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Année suivante"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Année précédente"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Le mois précédent"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Le mois prochain"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuler"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Supprimer"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Sélectionnez les minutes"</string>
<string name="select_day" msgid="7774759604701773332">"Sélectionnez un mois et un jour"</string>
<string name="select_year" msgid="7952052866994196170">"Sélectionnez une année"</string>
- <string name="item_is_selected" msgid="949687401682476608">"« <xliff:g id="ITEM">%1$s</xliff:g> » a été sélectionné"</string>
<string name="deleted_key" msgid="7659477886625566590">"« <xliff:g id="KEY">%1$s</xliff:g> » a été supprimé"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage de cet écran, appuyez de manière prolongée sur Retour et Aperçu simultanément."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 115c567..302c7c1 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"désactiver l\'indicateur d\'émission LED lorsque la caméra est en cours d\'utilisation"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permet à une application système préinstallée de désactiver l\'indicateur LED d\'utilisation de la caméra."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"désactiver définitivement la tablette"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"désactiver le téléviseur de manière définitive"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"désactiver définitivement le téléphone"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet à l\'application de vérifier qu\'un package peut être installé."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associer à un vérificateur de package"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de package. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"valider le filtre d\'intention"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permet à l\'application de vérifier si un filtre d\'intention est validé ou non."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"s\'associer pour valider filtre d\'intention"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permet à l\'application autorisée de demander la validation des filtres d\'intention. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"accéder aux ports série"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permet à l\'application autorisée d\'accéder aux ports série avec l\'API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accès externe fournisseurs de contenu"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Jour précédent"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Année suivante"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Année précédente"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mois précédent"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mois suivant"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuler"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Supprimer"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Sélectionner des minutes"</string>
<string name="select_day" msgid="7774759604701773332">"Sélectionner un mois et un jour"</string>
<string name="select_year" msgid="7952052866994196170">"Sélectionner une année"</string>
- <string name="item_is_selected" msgid="949687401682476608">"\"<xliff:g id="ITEM">%1$s</xliff:g>\" sélectionné"</string>
<string name="deleted_key" msgid="7659477886625566590">"\"<xliff:g id="KEY">%1$s</xliff:g>\" supprimé"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage, appuyez de manière prolongée et simultanée sur \"Retour\" et \"Aperçu\"."</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index a282039..a253939 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite á aplicación tomar imaxes e vídeos coa cámara. Con este permiso a aplicación pode utilizar a cámara en calquera momento sen a túa confirmación."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desactivar LED indicador de transmisión cando se está utilizando a cámara"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite a unha aplicación do sistema preinstalada desactivar o LED indicador de uso da cámara."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactivar o tablet permanentemente"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"desactivar a televisión permanentemente"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar o teléfono permanentemente"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite á aplicación verificar se un paquete é instalable."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a un verificador de paquetes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite ao propietario realizar solicitudes de verificadores de paquetes. As aplicacións normais non deberían necesitar este permiso."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificar filtro de intento"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite á aplicación comprobar se un filtro de intento está verificado ou non."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ligar a verificador de filtro de intento"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite ao propietario realizar solicitudes de verificadores de filtros de intento. As aplicacións normais non deberían necesitar este permiso."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"acceder a portos serie"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permite que o propietario poida acceder aos portos serie usando a API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"acceder a provedores de contido externamente"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reducir día"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar ano"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reducir ano"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mes anterior"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mes seguinte"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Seleccionar minutos"</string>
<string name="select_day" msgid="7774759604701773332">"Seleccionar mes e día"</string>
<string name="select_year" msgid="7952052866994196170">"Seleccionar ano"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionado"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar a pantalla, mantén premido Atrás e Visión xeral ao mesmo tempo."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 943ed28..7407d23 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ऐप्स को कैमरे से चित्र और वीडियो लेने देता है. यह अनुमति ऐप्स को किसी भी समय आपकी पुष्टि के बिना कैमरे का उपयोग करने देती है."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"कैमरा उपयोग में होने पर संचारण संकेतक LED अक्षम करें"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"पहले से इंस्टॉल किए गए सिस्टम ऐप्स को कैमरे को संकेतक LED का उपयोग करने से अक्षम करती है."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"स्थायी रूप से टेबलेट अक्षम करें"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"टीवी को स्थायी रूप से अक्षम करना"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"फ़ोन को स्थायी रूप से अक्षम करें"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"एप्लिकेशन को इंस्टॉल करने योग्य पैकेज सत्यापित करने देता है."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"पैकेज प्रमाणक से आबद्ध करें"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"लक्ष्य फ़िल्टर सत्यापित करें"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ऐप को जांच करने देती है कि कोई लक्ष्य फ़िल्टर सत्यापित है या नहीं."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"लक्ष्य फ़िल्टर प्रमाणक से आबद्ध करें"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"धारक को लक्ष्य फ़िल्टर प्रमाणक के अनुरोध की अनुमति देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"सीरियल पोर्ट पर पहुंचें"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API का उपयोग करके धारक को सीरियल पोर्ट पर पहुंच प्रदान करता है."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"बाह्य रूप से सामग्री प्रदाताओं पर पहुंच"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"दिन कम करें"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"वर्ष बढ़ाएं"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"वर्ष कम करें"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"पिछला महीना"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"अगला महीना"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"अभी नहीं"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"हटाएं"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"मिनट चुनें"</string>
<string name="select_day" msgid="7774759604701773332">"माह और दिन चुनें"</string>
<string name="select_year" msgid="7952052866994196170">"वर्ष चुनें"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> चयनित"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> को हटा दिया गया"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्यस्थल का <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"इस स्क्रीन को अनपिन करने के लिए, एक ही समय में वापस जाएं और अवलोकन को स्पर्श करके रखें."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index bc3f839..a935a5a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -586,6 +586,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogućuje snimanje slika i videozapisa fotoaparatom. Ta dozvola aplikaciji omogućuje upotrebu fotoaparata u bilo kojem trenutku bez vašeg odobrenja."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"onemogućavanje lampice pokazivača prijenosa kada je fotoaparat u upotrebi"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Omogućuje unaprijed instaliranim aplikacijama sustava onemogućavanje lampice pokazivača upotrebe fotoaparata."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trajno onemogući tabletni uređaj"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"trajno onemogućivanje televizora"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"trajno onemogućavanje telefona"</string>
@@ -1137,6 +1139,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Aplikaciji omogućuje da provjeri je li paket moguće instalirati."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vezano uz paketnu provjeru"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Nositelju omogućuje da traži paketnu provjeru. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"potvrditi filtar namjere"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Omogućuje aplikaciji da provjeri je li filtar namjere potvrđen."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"vezati se uz potvrdu filtara namjere"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Omogućuje nositelju zahtijevanje potvrde filtara namjere. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"pristup serijskim priključcima"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Rukovatelju omogućuje pristup serijskim priključcima pomoću značajke SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"pristup pružateljima sadržaja izvana"</string>
@@ -1569,6 +1575,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Smanjenje dana"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Povećanje godine"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Smanjenje godine"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Prethodni mjesec"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Sljedeći mjesec"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Odustani"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Izbriši"</string>
@@ -1822,7 +1830,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Odaberite minute"</string>
<string name="select_day" msgid="7774759604701773332">"Odaberite mjesec i dan"</string>
<string name="select_year" msgid="7952052866994196170">"Odaberite godinu"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Odabrana je stavka <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Izbrisan je broj <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Da biste otkvačili ovaj zaslon, istovremeno dodirnite i zadržite Natrag i Pregled."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index df2d876..9d5f0c9 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Lehetővé teszi az alkalmazás számára, hogy a fényképezőgéppel fotókat és videókat készítsen. Az engedéllyel rendelkező alkalmazás bármikor, az Ön jóváhagyása nélkül használhatja a fényképezőgépet."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"átviteljelző LED letiltása, ha a kamera használatban van"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Lehetővé teszi egy előre telepített rendszeralkalmazás számára, hogy letiltsa a kamerahasználatot jelző LED-et."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"a táblagép végleges deaktiválása"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"a tévé teljes letiltása"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"telefon végleges letiltása"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lehetővé teszi az alkalmazás számára, hogy ellenőrizze, egy csomag telepíthető-e."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"egy csomaghitelesítőhöz kötődnek"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lehetővé teszi, hogy a tulajdonos kérelmeket nyújtson be a csomag hitelesítőivel kapcsolatban. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"„intent filter” hitelesítése"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Lehetővé teszi annak ellenőrzését egy alkalmazás számára, hogy egy „intent filter” hitelesítve van-e."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"rögzítés egy „intent filter” hitelesítőhöz"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Lehetővé teszi, hogy a tulajdonos kéréseket kezdeményezzen az „intent filter” hitelesítőkkel kapcsolatban. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"soros portok elérése"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Lehetővé teszi a tulajdonos számára a soros portok elérését a SerialManager API segítségével."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"tartalomszolgáltatók külső elérése"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Dátum értékének csökkentése"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Év értékének növelése"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Év értékének csökkentése"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Előző hónap"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Következő hónap"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Mégse"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Perc kiválasztása"</string>
<string name="select_day" msgid="7774759604701773332">"Válassza ki a hónapot és a napot"</string>
<string name="select_year" msgid="7952052866994196170">"Válassza ki az évet"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> kiválasztva"</string>
<string name="deleted_key" msgid="7659477886625566590">"A(z) <xliff:g id="KEY">%1$s</xliff:g> érték törölve"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"A képernyő rögzítésének feloldásához tartsa lenyomva a Vissza és az Áttekintés lehetőséget egyszerre."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 9a59303..c1ce22f 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Թույլ է տալիս հավելվածին ֆոտոխցիկով լուսանկարել և տեսանկարել: Այս թույլտվությունը հնարավորություն է տալիս հավելվածին օգտագործել ֆոտոխցիկը ցանկացած ժամանակ` առանց ձեր հաստատման:"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"անջատել փոխանցող LED ցուցիչը, երբ ֆոտոխցիկը օգտագործվում է"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Թույլ է տալիս նախապես տեղադրված համակարգային ծրագրին անջատել ֆոտոխցիկի օգտագործման LED ցուցիչը:"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"մշտապես անջատել գրասալիկը"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"մշտապես անջատել հեռուստացույցը"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ընդմիշտ կասեցնել հեռախոսը"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Թույլ է տալիս հավելվածին հաստատել, որ փաթեթը տեղադրելի է:"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"միանալ փաթեթի ստուգիչին"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Թույլ է տալիս սեփականատիրոջը փաթեթի ստուգիչների հարցում կատարել: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"մուտք գործել հաջորդական միացքներ"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Թույլ է տալիս սեփականատիրոջը մուտք գործել հաջորդական միացքներ` օգտագործելով SerialManager API-ը:"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"դրսից մատչել բովանդակություն տրամադրողներին"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Նվազեցնել օրը"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Աճեցնել տարին"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Նվազեցնել տարին"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Չեղարկել"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ջնջել"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Ընտրեք րոպեն"</string>
<string name="select_day" msgid="7774759604701773332">"Ընտրեք ամիսն ու օրը"</string>
<string name="select_year" msgid="7952052866994196170">"Ընտրեք տարին"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Ընտրված է <xliff:g id="ITEM">%1$s</xliff:g> տարրը"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> թիվը ջնջված է"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Աշխատանքային <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Այս էկրան ապամրացնելու համար միաժամանակ հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f1775d0..86b642f 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Memungkinkan aplikasi mengambil gambar dan video dengan kamera. Izin ini memungkinkan aplikasi menggunakan kamera kapan saja tanpa konfirmasi Anda."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"nonaktifkan LED indikator transmisi saat kamera digunakan"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Izinkan aplikasi sistem yang sudah dipasang sebelumnya menonaktifkan LED indikator penggunaan kamera."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"noaktifkan tablet secara permanen"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"nonaktifkan TV secara permanen"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"nonaktifkan ponsel secara permanen"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Mengizinkan apl memverifikasi bahwa suatu paket dapat dipasang."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"mengikat ke pemverifikasi paket"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Mengizinkan pemegang mengajukan permintaan pemverifikasian paket. Tidak pernah dibutuhkan oleh apl normal."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifikasi maksud filter"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Mengizinkan aplikasi memeriksa apakah maksud filter diverifikasi atau tidak."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ikat ke pemverifikasi maksud filter"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Mengizinkan pemegangnya mengajukan permintaan pemverifikasi maksud filter. Tidak diperlukan untuk aplikasi normal."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"akses port serial"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Memungkinkan pemegangnya mengakses port serial menggunakan API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"mengakses penyedia konten dari luar"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Kurangi hari"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tambah tahun"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Kurangi tahun"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Bulan sebelumnya"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Bulan berikutnya"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Hapus"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Pilih menit"</string>
<string name="select_day" msgid="7774759604701773332">"Pilih bulan dan hari"</string>
<string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> dipilih"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> dihapus"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Kantor <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk melepas pin layar ini, sentuh lama tombol Kembali dan Ringkasan secara bersamaan."</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 0797db1..8f17e90 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Leyfir forriti að taka myndir og myndskeið með myndavélinni. Þessi heimild leyfir forritinu að nota myndavélina hvenær sem er án þinnar heimildar."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"slökkva á gaumljósi flutnings þegar myndavél er í notkun"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Leyfir foruppsettu kerfisforriti að gera gaumljós myndavélarinnar óvirkt."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"gera spjaldtölvuna varanlega óvirka"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"gera sjónvarpið varanlega óvirkt"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"gera símann varanlega óvirkan"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Leyfir forriti að staðfesta að hægt sé að setja upp pakka."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bindast pakkasannvottun"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Leyfir handhafa að búa til beiðnir fyrir pakkastaðfestingu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"staðfesta ásetningssíu"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Leyfir forriti að athuga hvort ásetningssía er staðfest eða ekki."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bindast staðfestingu ásetningssíu"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Leyfir handhafa að búa til beiðnir fyrir staðfestingu ásetningssíu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"aðgangur að raðtengjum"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Leyfir forriti að fá aðgang að raðtengjum með forritaskilum SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ytri aðgangur að efnisveitum"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Niður um dag"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Upp um ár"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Niður um ár"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Fyrri mánuður"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Næsti mánuður"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Hætta við"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eyða"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Veldu mínútur"</string>
<string name="select_day" msgid="7774759604701773332">"Veldu mánuð og dag"</string>
<string name="select_year" msgid="7952052866994196170">"Veldu ár"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> valið"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eytt"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Til að taka lásinn af þessari skjámynd skaltu halda inni Til baka og Yfirliti samtímis."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0269cc7..adabdfb 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Consente all\'applicazione di scattare foto e riprendere video con la fotocamera. Questa autorizzazione consente all\'applicazione di utilizzare la fotocamera in qualsiasi momento senza la tua conferma."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"disabilitazione del LED di indicazione della trasmissione quando la fotocamera è in uso"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Consente a un\'applicazione di sistema preinstallata di disabilitare il LED che indica l\'utilizzo della fotocamera."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"disattivazione definitiva tablet"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"disattivazione definitiva della TV"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"disattivazione telefono"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Consente all\'applicazione di verificare se un pacchetto è installabile."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associazione a verifica pacchetto"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Consente al proprietario di effettuare richieste relative alle verifiche dei pacchetti. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifica filtro di intent"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Consente all\'app di verificare se un filtro di intent è stato verificato o meno."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"collegamento a uno strumento di verifica dei filtri di intent"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Consente al proprietario di effettuare richieste relative agli strumenti di verifica dei filtri di intent. Non dovrebbe mai essere necessario per applicazioni normali."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"accesso alle porte seriali"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permette al proprietario di accedere alle porte seriali utilizzando l\'API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accesso a fornitori di contenuti esterni"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Riduci giorno"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumenta anno"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Riduci anno"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mese precedente"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mese successivo"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annulla"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Canc"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Seleziona i minuti"</string>
<string name="select_day" msgid="7774759604701773332">"Seleziona mese e giorno"</string>
<string name="select_year" msgid="7952052866994196170">"Seleziona anno"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Elemento selezionato: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminato"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> lavoro"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Per sbloccare questa schermata, tocca e tieni premute contemporaneamente le opzioni Indietro e Panoramica."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 54367fe..007245b 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -587,6 +587,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"מאפשר לאפליקציה לצלם תמונות וסרטונים באמצעות המצלמה. אישור זה מאפשר לאפליקציה להשתמש במצלמה בכל עת ללא אישורך."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"השבת את נורית מצב השידור כשהמצלמה בשימוש"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"מתיר לאפליקציית מערכת המותקן מראש להשבית את השימוש של המצלמה בנורית המצב."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"השבת טאבלט לצמיתות"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"השבתה של הטלוויזיה לצמיתות"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"השבת טלפון לצמיתות"</string>
@@ -760,8 +762,8 @@
<string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"אין אפשרות לעבד. נסה שוב."</string>
<string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"החומרה לא זמינה."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"לא ניתן לאחסן טביעת אצבע. הסר טביעת אצבע קיימת."</string>
- <string name="fingerprint_error_timeout" msgid="3927186043737732875">"חלף זמן קצוב לתפוגה של טביעת אצבע. נסה שוב."</string>
- <string name="fingerprint_error_vendor" msgid="3175724710791609491">"חלף זמן קצוב לתפוגה של טביעת אצבע. נסה שוב."</string>
+ <string name="fingerprint_error_timeout" msgid="3927186043737732875">"חלף הזמן הקצוב לטביעת אצבע. נסה שוב."</string>
+ <string name="fingerprint_error_vendor" msgid="3175724710791609491">"חלף הזמן הקצוב לטביעת אצבע. נסה שוב."</string>
<string-array name="fingerprint_error_vendor">
<item msgid="5804600450373644614">"הודעת שגיאה ספציפית לספק."</item>
</string-array>
@@ -1138,6 +1140,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"מאפשר לאפליקציה לאמת שחבילה ניתנת להתקנה."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"הכפפה למאמת חבילה"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"מאפשר למשתמש להגיש בקשות של מאמתי חבילות. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"אימות של מסנן כוונה"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"מאפשר לאפליקציה לבדוק אם מסנן כוונה אומת או לא."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"הכפפה אל מאמת של מסנן כוונה"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"מאפשר למשתמש להגיש בקשות של מאמתי סינון כוונה. לעולם לא אמור להיות נחוץ לאפליקציות רגילות."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"גישה ליציאות טוריות"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"מאפשר לבעלים לגשת ליציאות טוריות באמצעות ממשק ה- API של SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"גישה לספקי תוכן באופן חיצוני"</string>
@@ -1577,6 +1583,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"הפחת יום"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"הוסף שנה"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"הפחת שנה"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"החודש הקודם"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"החודש הבא"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ביטול"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"מחק"</string>
@@ -1831,7 +1839,6 @@
<string name="select_minutes" msgid="3974345615920336087">"בחר דקות"</string>
<string name="select_day" msgid="7774759604701773332">"בחר חודש ויום"</string>
<string name="select_year" msgid="7952052866994196170">"בחר שנה"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> נבחר"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> נמחק"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"עבודה <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"כדי לבטל את הקפאת המסך הזה, גע בו-זמנית נגיעה ממושכת ב\'הקודם\' ו\'סקירה\'."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e4ef4be..51055d8 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"カメラでの写真と動画の撮影をアプリに許可します。これにより、アプリが確認なしでいつでもカメラを使用できるようになります。"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"カメラの使用中に通信インジケータLEDを無効にする"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"カメラ使用インジケータLEDを無効にすることをプレインストールされているシステムアプリに許可します。"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"タブレットを完全に無効化"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"テレビを完全に無効化"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"端末を永続的に無効にする"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"パッケージがインストール可能かどうか確認することをアプリに許可します。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"パッケージベリファイアにバインド"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"パッケージベリファイアのリクエストを所有者に許可します。通常のアプリでは不要です。"</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"インテントフィルタの検証"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"インテントフィルタが検証されているかどうかを確認することをアプリに許可します。"</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"インテントフィルタベリファイアにバインド"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"インテントフィルタベリファイアのリクエストを所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_serialPort" msgid="546083327654631076">"シリアルポートへのアクセス"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager APIを使用してシリアルポートにアクセスすることを所有者に許可します。"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"コンテンツプロバイダへの外部アクセス"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"1日戻します"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"1年進めます"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"1年戻します"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"前月"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"翌月"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"キャンセル"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"削除"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"分を選択"</string>
<string name="select_day" msgid="7774759604701773332">"月と日を選択"</string>
<string name="select_year" msgid="7952052866994196170">"年を選択"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g>を選択しました"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g>を削除しました"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"仕事の<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"この画面の固定を解除するには[戻る]と[最近]を同時に押し続けます。"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 8f9e8cf..7a0483b 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"აპს შეეძლება კამერით სურათისა და ვიდეოს გადაღება. ეს ნებართვა აპს უფლებას აძლევს, ნებისმიერ დროს გამოიყენოს კამერა თქვენი დადასტურების გარეშე."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"კამერის გამოყენებისას გადამცემი ინდიკატორის LED გათიშვა"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ნებას რთავს წინასწარ დაყენებული სისტემის აპლიკაციას, გამორთოს კამერის გამოყენების ინდიკატორი LED."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"მუდმივად გამორთული ტაბლეტი"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"ტელევიზორის მუდმივად გამორთვა"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ტელეფონის სამუდამოდ დეაქტივაცია"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"აპს შეუძლია დაადასტუროს პაკეტის დაყანების შესაძლებლობა."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"პაკეტების ვერიფიკატორებთან დაკავშირება"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"მფლობელს შეეძლება პაკეტის ვერიფიკატორების მოთხოვნა. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"სერიულ პორტებზე წვდომა"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"მფლობელს შეეძლება სერიულ პორტებზე წვდომა სერიული მენეჯერის API-ის გამოყენებით."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"კონტენტის მომწოდებლებთან გარედან წვდომა"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"დღის მოკლება"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"წლის მომატება"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"წლის მოკლება"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"გაუქმება"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"წაშლა"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"აირჩიეთ წუთები"</string>
<string name="select_day" msgid="7774759604701773332">"აირჩიეთ თვე და რიცხვი"</string>
<string name="select_year" msgid="7952052866994196170">"აირჩიეთ წელი"</string>
- <string name="item_is_selected" msgid="949687401682476608">"არჩეულია <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> წაიშალა"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"მიმაგრების გასაუქმებლად ერთდროულად შეეხეთ და არ აუშვათ ღილაკებს „უკან“ და „მიმოხილვა“."</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 45f91b5..f843dbe 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Қолданбаға камераны қолданып, фотосурет немесе бейне жазу мүмкіндігін береді. Бұл рұқсат камераны кез келген уақытта сіздің құптауыңызды қажет етпей қолдану мүмкіндігін береді."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"камера қолданыста болғанда жарық диодты шамы бар көрсеткішті өшіру"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Алдын ала орнатылған жүйе қолданбасына камераның жарық диодты көрсеткішті қолдануын өшіру мүмкіндігін береді."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"планшетті мүлдем өшіру"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"ТД біржола өшіру"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"телефонды мүлдем өшіру"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Қолданбаға буманы орнатуға болатынын тексеруге рұқсат береді."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"жинақ растау қызметіне байланыстыру"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Пайдаланушыға бума верификаторларының сұрауларын жасауға рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"сериялық портқа кіру"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Пайдаланушыға Сериялық Менеджер қолданба бағдарламалау интерфейсін қолданып, сериялық порттарға кіру мүмкіндігін ұсынады."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"мазмұн жабдықтаушыларға сырттан қатынасу"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Күн азайту"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Жыл арттыру"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Жыл азайту"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Өшіру"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Жою"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Минут таңдау"</string>
<string name="select_day" msgid="7774759604701773332">"Ай мен күнді таңдау"</string>
<string name="select_year" msgid="7952052866994196170">"Жыл таңдау"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> таңдалды"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> жойылды"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Жұмыс <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Осы экранды босату үшін «Кері» және «Шолу» пәрмендерін бір уақытта түртіп, ұстап тұрыңыз."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 9ccc1ab..dffdf5e 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ឲ្យកម្មវិធីថតរូប និងវីដេអូដោយប្រើម៉ាស៊ីនថត។ វាឲ្យកម្មវិធីប្រើម៉ាស៊ីនថតនៅពេលណាមួយដោយគ្មានការបញ្ជាក់របស់អ្នក។"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"បិទពន្លឺបង្ហាញការបញ្ជូនពេលម៉ាស៊ីនថតកំពុងប្រើ"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ឲ្យកម្មវិធីប្រព័ន្ធដែលបានដំឡើងរួចបិទ LED បង្ហាញការប្រើម៉ាស៊ីនថត។"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"បិទកុំព្យូទ័របន្ទះជាអចិន្ត្រៃយ៍"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"បិទដំណើរការទូរទស្សន៍ជាអចិន្ត្រៃយ៍"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"បិទទូរស័ព្ទជាអចិន្ត្រៃយ៍"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ឲ្យកម្មវិធីផ្ទៀងផ្ទាត់កញ្ចប់ដែលអាចដំឡើងបាន។"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ចងទៅកម្មវិធីផ្ទៀងផ្ទាត់កញ្ចប់"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ឲ្យម្ចាស់ស្នើកម្មវិធីផ្ទៀងផ្ទាត់កញ្ចប់។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"ចូលដំណើរការច្រកស៊េរី"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"អនុញ្ញាតឱ្យចូលដំណើរការទៅកាន់ច្រកសៀរៀលដោយប្រើ SerialManager API ។"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ចូលដំណើរការក្រុមហ៊ុនផ្ដល់មាតិកាខាងក្រៅ"</string>
@@ -1563,6 +1573,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"បន្ថយថ្ងៃ"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"បង្កើនឆ្នាំ"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"បន្ថយឆ្នាំ"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះបង់"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"លុប"</string>
@@ -1815,7 +1829,6 @@
<string name="select_minutes" msgid="3974345615920336087">"ជ្រើសនាទី"</string>
<string name="select_day" msgid="7774759604701773332">"ជ្រើសខែ និងថ្ងៃ"</string>
<string name="select_year" msgid="7952052866994196170">"ជ្រើសឆ្នាំ"</string>
- <string name="item_is_selected" msgid="949687401682476608">"បានជ្រើស <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"បានលុប <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"កន្លែងធ្វើការ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"ដើម្បីមិនភ្ជាប់អេក្រង់នេះ ប៉ះ ហើយសង្កត់ថយក្រោយ និងទិដ្ឋភាពនៅពេលតែមួយ។"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 9c10119..cde560f 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ಕ್ಯಾಮರಾ ಮೂಲಕ ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಈ ಅನುಮತಿಯು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ಕ್ಯಾಮರಾ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ಪ್ರಸಾರ ಸೂಚಕ LED ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ಕ್ಯಾಮರಾ ಬಳಕೆ ಸೂಚಕ LED ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಪೂರ್ವ-ಸ್ಥಾಪಿತ ಸಿಸ್ಟಂ ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ಶಾಶ್ವತವಾಗಿ ಟ್ಯಾಬ್ಲೆಟ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"ಟಿವಿಯನ್ನು ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ಶಾಶ್ವತವಾಗಿ ಫೋನ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ಪ್ಯಾಕೇಜ್ ಅನ್ನು ಸ್ಥಾಪಿಸಬಹುದಾದ ಪರಿಶೀಲನೆಯನ್ನು ಅಪ್ಲಿಕೇಶನ್ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ಪ್ಯಾಕೇಜ್ ಪರಿಶೀಲಕಕ್ಕೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ಪ್ಯಾಕೇಜ್ ಪರಿಶೀಲನಾಗಾರರ ವಿನಂತಿಗಳನ್ನು ಮಾಡಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ಉದ್ದೇಶಿತ ಫಿಲ್ಟರ್ ಪರಿಶೀಲಿಸಿ"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ಇಂಟರ್ನೆಟ್ ಫಿಲ್ಟರ್ ಅನ್ನು ಪರಿಶೀಲಿಸಲಾಗಿದೆಯೇ ಅಥವಾ ಇಲ್ಲವೆ ಎಂಬುದನ್ನು ಪರೀಕ್ಷಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ಉದ್ದೇಶಿತ ಫಿಲ್ಟರ್ ಪರಿಶೀಲಕವನ್ನು ಪ್ರತಿಬಂಧಿಸಿ"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ಉದ್ದೇಶಿತ ಫಿಲ್ಟರ್ ಪರಿಶೀಲನಾಗಾರರ ವಿನಂತಿಗಳನ್ನು ಮಾಡಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"ಸರಣಿ ಪೋರ್ಟ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API ಬಳಸಿಕೊಂಡು ಸರಣಿ ಪೋರ್ಟ್ಗಳಿಗೆ ಪ್ರವೇಶ ಪಡೆಯಲು ಹೊಂದಿರುವವರಿಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ವಿಷಯ ಪೂರೈಕೆದಾರರನ್ನು ಬಾಹ್ಯ ರೀತಿಯಲ್ಲಿ ಪ್ರವೇಶಿಸಿ"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ದಿನವನ್ನು ಕಡಿಮೆಮಾಡಿ"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"ವರ್ಷವನ್ನು ಹೆಚ್ಚಿಸಿ"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ವರ್ಷವನ್ನು ಕಡಿಮೆಮಾಡಿ"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ಹಿಂದಿನ ತಿಂಗಳು"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"ಮುಂದಿನ ತಿಂಗಳು"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ರದ್ದುಮಾಡು"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ಅಳಿಸು"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"ನಿಮಿಷಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="select_day" msgid="7774759604701773332">"ತಿಂಗಳು ಮತ್ತು ದಿನವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="select_year" msgid="7952052866994196170">"ವರ್ಷವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ಅಳಿಸಲಾಗಿದೆ"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"ಕೆಲಸ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"ಈ ಪರದೆಯನ್ನು ಅನ್ಪಿನ್ ಮಾಡಲು, ‘ಹಿಂದೆ’ ಮತ್ತು ‘ಸಮಗ್ರ ನೋಟ’ವನ್ನು ಏಕಕಾಲದಲ್ಲಿ ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 6da084e..cf3a98c 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"앱이 카메라로 사진과 동영상을 찍을 수 있도록 허용합니다. 이 권한을 사용하면 앱이 언제든지 사용자의 확인 없이 카메라를 사용할 수 있습니다."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"카메라를 사용할 때 전송 표시 LED 사용 중지"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"사전 설치된 시스템 애플리케이션에서 카메라 사용 표시 LED를 사용 중지하도록 허용합니다."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"영구적으로 태블릿 사용 안함"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"TV를 영구적으로 사용 중지"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"휴대전화를 영구적으로 사용 중지"</string>
@@ -747,15 +749,15 @@
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"사용할 지문 템플릿의 추가 및 삭제 메소드를 앱에서 실행하도록 허용합니다."</string>
<string name="permlab_useFingerprint" msgid="3150478619915124905">"지문 하드웨어 사용"</string>
<string name="permdesc_useFingerprint" msgid="9165097460730684114">"앱에서 지문 하드웨어를 인증에 사용하도록 허용합니다."</string>
- <string name="fingerprint_acquired_partial" msgid="735082772341716043">"지문이 일부만 감지되었습니다. 다시 시도해 주세요."</string>
- <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"지문을 처리할 수 없습니다. 다시 시도해 주세요."</string>
- <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"지문 센서가 더럽습니다. 깨끗이 닦고 다시 시도하세요."</string>
+ <string name="fingerprint_acquired_partial" msgid="735082772341716043">"지문이 일부만 인식되었습니다. 다시 시도해 주세요."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"지문 센서를 깨끗이 닦고 다시 시도하세요."</string>
<string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"손가락을 너무 빨리 움직였습니다. 다시 시도해 주세요."</string>
<string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"손가락을 너무 느리게 움직였습니다. 다시 시도해 주세요."</string>
<string-array name="fingerprint_acquired_vendor">
<item msgid="2892952818207766996">"공급업체별 획득 오류 메시지 0"</item>
</string-array>
- <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"처리할 수 없습니다. 다시 시도하세요."</string>
+ <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"인식할 수 없습니다. 다시 시도하세요."</string>
<string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"하드웨어를 사용할 수 없습니다."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"지문을 저장할 수 없습니다. 기존 지문을 삭제하세요."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"지문 인식 시간이 초과되었습니다. 다시 시도하세요."</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"앱이 패키지가 설치 가능한지 확인할 수 있도록 허용합니다."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"패키지 인증 연결"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"권한을 가진 프로그램이 패키지 인증을 요청할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"직렬 포트에 액세스"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API를 사용하여 권한을 가진 프로그램이 직렬 포트에 액세스할 수 있도록 합니다."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"외부에서 콘텐츠 제공자에 액세스"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"\'일\'을 줄입니다."</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"\'연도\'를 늘립니다."</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"\'연도\'를 줄입니다."</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt 키"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"취소"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete 키"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"분 선택"</string>
<string name="select_day" msgid="7774759604701773332">"월/일 선택"</string>
<string name="select_year" msgid="7952052866994196170">"연도 선택"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g>이(가) 선택됨"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> 삭제됨"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"업무용 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"화면 고정을 해제하려면 \'뒤로\'와 \'개요\'를 동시에 길게 터치합니다."</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 7696fbb..a2e671e 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -750,6 +750,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Колдонмого камера аркылуу видео жана сүрөт тартуу уруксатын берет. Бул уруксат, камераны каалаган убакта, сиздин ырастооңузсуз колдонуу уруксатын берет."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"өткөрүүчүнүн LED индикаторун камера иштеп жатканда өчүрүү"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Камтылган системалык колдонмолорго камеранын LED\'ди колдонуусун өчүрүү мүмкүнчүлүгүн берет."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<!-- no translation found for permlab_brick (2961292205764488304) -->
<skip />
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"сыналгыны биротоло өчүрүү"</string>
@@ -1463,6 +1465,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Колдонмого топтомдун орнотула тургандыгын текшерүү мүмкүнчүлүгүн берет."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"таңгак текшерүүчүгө байлаштыруу"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Кармоочуга топтом текшергичтеринин атынан өтүнүү мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"сериялык портторго жетүү"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Ээсине SerialManager API\'ни колдонуп, серия портуна жеткенге уруксат берүү."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"тышкы контент провайдерлерге жетки алуу"</string>
@@ -2057,6 +2067,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Күндү азайтуу"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Жылды жогорулатуу"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Жылды азайтуу"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Айнуу"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Жок кылуу"</string>
@@ -2328,7 +2342,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Мүнөттөрдү тандаңыз"</string>
<string name="select_day" msgid="7774759604701773332">"Ай жана күндү тандаңыз"</string>
<string name="select_year" msgid="7952052866994196170">"Жылды тандаңыз"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> тандалды"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> өчүрүлдү"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Бул экранды бошотуу үчүн Артка жана Көз жүгүртүүнү чогуу басып, кармап туруңуз."</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index b8e2cff..01097a0 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ອະນຸຍາດໃຫ້ແອັບຯຖ່າຍຮູບ ແລະວິດີໂອດ້ວຍກ້ອງຖ່າຍຮູບ. ການອະນຸຍາດນີ້ຈະອານຸຍາດໃຫ້ແອັບຯ ສາມາດໃຊ້ກ້ອງຖ່າຍຮູບໄດ້ຕະຫລອດເວລາ ໂດຍບໍ່ຕ້ອງຖ້າການຢືນຢັນຈາກທ່ານ."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ປິດໄຟສັນຍານ LED ເມື່ອນຳໃຊ້ກ້ອງ"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນທີ່ມາກັບໂຕເຄື່ອງ ປິດການນຳໃຊ້ໄຟ LED ໃນກ້ອງຖ່າຍຮູບ."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ປິດການນຳໃຊ້ແທັບເລັດຖາວອນ"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"ປິດໃຊ້ງານໂທລະພາບຖາວອນ"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ປິດການເຮັດວຽກຂອງໂທລະສັບຖາວອນ"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ອະນຸຍາດໃຫ້ແອັບຯຢືນຢັນວ່າແພັກເກດໃດນຶ່ງ ສາມາດຕິດຕັ້ງໄດ້."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ເຊື່ອມໂຍງກັບໂຕຢືນຢັນແພັກເກດ"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຮັດການຮ້ອງຂໍໂຕຢືນຢັນແພັກເກັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ຢືນຢັນການກັ່ນຕອງຕາມຕັ້ງ"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ອະນຸຍາດໃຫ້ແອັບກວດເບິ່ງວ່າ ການກັ່ນຕອງຕາມຕັ້ງໃຈໄວ້ໄດ້ຮັບການຢືນຢັນ ຫຼືບໍ່."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ຜູກມັດກັບໂຕຢືນຢັນການກັ່ນຕອງຕາມຕັ້ງໃຈ"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຮັດການຮ້ອງຂໍໂຕຢືນຢັນການກັ່ນຕອງຕາມຕັ້ງໃຈ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"ເຂົ້າເຖິງພອດຊີຣຽວ"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສາມາດເຂົ້າເບິ່ງ serial ports ໂດຍການນຳໃຊ້ SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ເຂົ້າເຖິງຜູ່ສະໜອງເນື້ອຫາພາຍນອກ"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ຫຼຸດຈຳນວນມື້"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"ເພີ່ມປີຂຶ້ນ"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ຫຼຸດຈຳນວນປີ"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ເດືອນແລ້ວ"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"ເດືອນໜ້າ"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ຍົກເລີກ"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ລຶບ"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"ເລືອກນາທີ"</string>
<string name="select_day" msgid="7774759604701773332">"ເລືອກເດືອນ ແລະ ວັນ"</string>
<string name="select_year" msgid="7952052866994196170">"ເລືອກປີ"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ຖືກເລືອກແລ້ວ"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ຖືກລຶບແລ້ວ"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"ບ່ອນເຮັດວຽກ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"ເພື່ອຖອດການປັກໝຸດໜ້າຈໍນີ້, ສຳຜັດປຸ່ມ ກັບຄືນ ແລະ ພາບຮວມ ຄ້າງໄວ້ພ້ອມກັນ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f1f81bd..d387c910 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -587,6 +587,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Leidžiama programai fotografuoti ir filmuoti kamera. Šis leidimas suteikia teisę programai naudoti kamerą bet kada be jūsų patvirtinimo."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"neleisti perduoti LED indikatoriaus, kai naudojamas fotoaparatas"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Leidžiama iš anksto įdiegtai sistemos programai išjungti fotoaparato naudojimo indikatoriaus LED."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"visam laikui neleisti planšetinio kompiuterio"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"visam laikui išjungti TV"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"visam laikui išjungti telefoną"</string>
@@ -1138,6 +1140,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Leidžiama programai patikrinti, ar paketą galima įdiegti."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"susaistyti su paketo tikrinimo programa"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Savininkui leidžiama teikti užklausas patikrinti paketą. Įprastoms programoms to neturėtų prireikti."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"patvirtinti tikslinį filtrą"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Leidžiama programai patikrinti, ar tikslinis filtras patvirtintas."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"priskirti tikslinio filtro tvirtin. pr."</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Savininkui leidžiama teikti užklausas patvirtinti tikslinį filtrą. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"pasiekti nuosekliuosius prievadus"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Leidžiama savininkui pasiekti nuosekliuosius prievadus naudojant „SerialManager“ API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"pasiekti turinio teikėjus iš išorės"</string>
@@ -1577,6 +1583,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Sumažinti dienų skaičių"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Padidinti metų skaičių"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Sumažinti metų skaičių"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Ankstesnis mėnuo"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Kitas mėnuo"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Atšaukti"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ištrinti"</string>
@@ -1831,7 +1839,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Pasirinkite minutes"</string>
<string name="select_day" msgid="7774759604701773332">"Pasirinkite mėnesį ir dieną"</string>
<string name="select_year" msgid="7952052866994196170">"Pasirinkite metus"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Pasirinkta: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Ištrinta: <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Jei norite atsegti šį ekraną, vienu metu palieskite ir palaikykite „Atgal“ ir „Apžvalga“."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a55ea95..c64ea9e 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -586,6 +586,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ļauj lietotnei uzņemt attēlus un videoklipus ar kameru. Ar šo atļauju lietotne var jebkurā brīdī izmantot kameru bez jūsu apstiprinājuma."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Atspējot pārraidīšanas LED indikatoru, kad kamera tiek izmantota"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Ļauj iepriekš instalētai sistēmas lietojumprogrammai atspējot LED indikatoru, izmantojot kameru."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"neatgriezeniski atspējot planšetdatoru"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"neatgriezeniski atspējot televizora darbību"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"neatgriezeniski atspējot tālruni"</string>
@@ -1137,6 +1139,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ļauj lietotnei verificēt, vai pakotne ir instalējama."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"saistīšana ar pakotnes verificētāju"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ļauj īpašniekam sūtīt pakotņu verificētāju pieprasījumus. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"piekļuve seriālajiem portiem"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Ļauj īpašniekam piekļūt seriālajiem portiem, izmantojot SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ārēji piekļūt satura nodrošinātājiem"</string>
@@ -1569,6 +1579,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Norādīt agrāku dienu"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Norādīt vēlāku gadu"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Norādīt agrāku gadu"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alternēšanas taustiņš"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Atcelt"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Dzēšanas taustiņš"</string>
@@ -1822,7 +1836,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Atlasiet minūtes."</string>
<string name="select_day" msgid="7774759604701773332">"Atlasiet mēnesi un dienu."</string>
<string name="select_year" msgid="7952052866994196170">"Atlasiet gadu."</string>
- <string name="item_is_selected" msgid="949687401682476608">"Atlasīts: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> tika dzēsts."</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbā: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Lai atspraustu šo ekrānu, vienlaicīgi pieskarieties pogām “Atpakaļ” un “Pārskats” un turiet tās."</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 76e05c8..a3cfd66 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Овозможува апликацијата да прави фотографии и да снима видеа со камерата. Оваа дозвола овозможува апликацијата да ја користи камерата во кое било време без ваша потврда."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"оневозможи пренесување на LED показателот при употреба на фотоапаратот"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Овозможува претходно инсталираниот систем на апликацијата да оневозможи фотоапаратот да го користи LED показателот."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"трајно оневозможи го таблетот"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"трајно оневозможи го телевизорот"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"трајно оневозможи го телефонот"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозволува апликацијата да провери дали пакетот може да се инсталира."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"врзи се со проверувач на пакет"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дозволува сопственикот да поднесува барања до верификаторите на пакети. Не треба да се користи за стандардни апликации."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"пристапи кон сериски порти"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Му овозможува на сопственикот да пристапи кон сериски порти употребувајќи го SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"однадвор пристапи кон обезбедувачи на содржина"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Намали ден"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Зголеми година"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Намали година"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Копче „Alt“"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Копче „Откажи“"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Копче „Избриши“"</string>
@@ -1815,7 +1829,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Избери минути"</string>
<string name="select_day" msgid="7774759604701773332">"Избери месец и ден"</string>
<string name="select_year" msgid="7952052866994196170">"Избери година"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Избрано <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Избришано <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Работа <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"За да го откачите екранот, допрете и задржете Назад и Краток преглед во исто време."</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index e18cc6c..9528628 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ക്യാമറ ഉപയോഗിച്ച് ചിത്രങ്ങളും വീഡിയോകളും എടുക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ ഏതുസമയത്തും ക്യാമറ ഉപയോഗിക്കാൻ ഈ അനുമതി അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ക്യാമറ ഉപയോഗത്തിലായിരിക്കുമ്പോൾ ട്രാൻസ്മിറ്റ് ഇൻഡിക്കേറ്റർ LED പ്രവർത്തനരഹിതമാക്കുക"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ക്യാമറയുടെ ഇൻഡിക്കേറ്റർ LED-യുടെ ഉപയോഗം പ്രവർത്തനരഹിതമാക്കാൻ മുൻകൂട്ടി ഇൻസ്റ്റാളുചെയ്ത സിസ്റ്റം അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ശാശ്വതമായി ടാബ്ലെറ്റ് പ്രവർത്തനരഹിതമാക്കുക"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"ടിവിയെ ശാശ്വതമായി പ്രവർത്തനരഹിതമാക്കുക"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ശാശ്വതമായി ഫോൺ പ്രവർത്തനരഹിതമാക്കുക"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ഒരു പാക്കേജ് ഇൻസ്റ്റാളുചെയ്യാനാവുന്നതാണോ എന്ന് പരിശോധിച്ചുറപ്പിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ഒരു പാക്കേജ് വെരിഫയറുമായി ബന്ധപ്പെടുത്തുക"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"പാക്കേജ് പരിശോധകരുടെ അഭ്യർത്ഥനകൾക്ക് ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ഉദ്ദേശിത ഫിൽട്ടർ പരിശോധിച്ചുറപ്പിക്കുക"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ഒരു ഉദ്ദേശിത ഫിൽട്ടർ പരിശോധിച്ചുറപ്പിച്ചോ ഇല്ലയോ എന്ന് പരിശോധിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ഒരു ഉദ്ദേശിത ഫിൽട്ടർ പരിശോധകനിലേക്ക് ബന്ധിപ്പിക്കുക"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ഉദ്ദേശിത ഫിൽട്ടർ പരിശോധകരുടെ അഭ്യർത്ഥനകൾക്ക് ഉടമയെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"സീരിയൽ പോർട്ടുകൾ ആക്സസ്സ് ചെയ്യുക"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API ഉപയോഗിക്കുന്ന സീരിയൽ പോർട്ടുകൾ ആക്സസ്സ് ചെയ്യാൻ ദാതാവിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ഉള്ളടക്ക ദാതാക്കളെ ബാഹ്യമായി ആക്സസ്സുചെയ്യുക"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ദിവസം കുറയ്ക്കുക"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"വർഷം വർദ്ധിപ്പിക്കുക"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"വർഷം കുറയ്ക്കുക"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"മുമ്പത്തെ മാസം"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"അടുത്ത മാസം"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"റദ്ദാക്കുക"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ഇല്ലാതാക്കുക"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"മിനിറ്റ് തിരഞ്ഞെടുക്കുക"</string>
<string name="select_day" msgid="7774759604701773332">"മാസവും ദിവസവും തിരഞ്ഞെടുക്കുക"</string>
<string name="select_year" msgid="7952052866994196170">"വർഷം തിരഞ്ഞെടുക്കുക"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> തിരഞ്ഞെടുത്തു"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ഇല്ലാതാക്കി"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"ഔദ്യോഗികം <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"ഈ സ്ക്രീൻ അൺപിൻ ചെയ്യാൻ \'മടങ്ങുക\', \'കാഴ്ച\' എന്നിവ ഒരേ സമയം സ്പർശിച്ച് പിടിക്കുക."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index da75a4a..37e9165 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Апп нь камераар зураг авах болон видео бичих боломжтой. Энэ зөвшөөрөл нь апп-д ямар ч үед таны зөвшөөрөлгүйгээр камер ашиглах боломжийг олгоно."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"камер ашиглаж байх үед дамжууллыг заагч LED-г идэвхгүй болгох"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Урьдчилан суусан систем аппликешн нь камер ашиглалтыг заасан LED-г идэвхгүй болгох боломжтой."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"таблетыг бүрмөсөн идэвхгүй болгох"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"телевиз-г бүр мөсөн идэвхгүй болгох"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"утсыг бүрмөсөн идэвхгүй болгох"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Апп нь багцыг суулгаж болох эсэхийг шалгах боломжтой."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"багц тулгагчтэй холбох"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Эзэмшигч нь багц тулгагчдад хүсэлт тавих боломжтой. Энгийн апп-д хэрэглэгдэхгүй."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"зориулалтын шүүлтүүрийг баталгаажуулах"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Зориулалтын шүүлтүүрийг баталгаажуулсан эсэхээс үл хамааран апп-д шалгах зөвшөөрөл өгөх"</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"зориулалтын шүүлтүүр шалгагч руу холбох"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Эзэмшигчид зориулалтын шүүлтүүрийг шалгах хүсэлт гаргахыг зөвшөөрөх. Энэ нь энгийн апп-уудад огт шаардлагагүй."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"сериал портруу хандах"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Эзэмшигч нь SerialManager API ашиглан сериал портод хандах боломжтой."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"контент нийлүүлэгчид гаднаас хандах"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Өдрийг бууруулах"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Жилийг өсгөх"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Жил бууруулах"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Өмнөх сар"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Дараагийн сар"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Цуцлах"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Устгах"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Минут сонгоно уу"</string>
<string name="select_day" msgid="7774759604701773332">"Сар болон өдрийг сонгоно уу"</string>
<string name="select_year" msgid="7952052866994196170">"Жилийг сонгоно уу"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> сонгогдсон"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> устсан"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Энэ дэлгэцийг цуцлахын тулд Буцах болон Тойм-д зэрэг хүрч барина."</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 2fe3f37..6ccf440 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"कॅमेर्यासह चित्रे आणि व्हिडिओ घेण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपल्या पुष्टीकरणाशिवाय कोणत्याही वेळी कॅमेरा वापरण्यासाठी अॅप ला परवानगी देते."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"कॅमेरा वापरात असताना प्रक्षेपण सूचक LED अक्षम करा"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"पूर्व-स्थापित सिस्टम अनुप्रयोगाला कॅमेरा वापर सूचक LED अक्षम करण्याची अनुमती देते."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"टॅब्लेट कायमचा अक्षम करा"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"टीव्ही कायमचा अक्षम करा"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"फोन कायमचा अक्षम करा"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"पॅकेज स्थापित करण्यायोग्य आहे हे सत्यापित करण्यासाठी अॅप ला अनुमती देते."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"पॅकेज सत्यापकावर प्रतिबद्ध व्हा"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"पॅकेज सत्यापित करणार्यांच्या विनंत्या करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यक नसते."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"हेतू फिल्टर सत्यापित करा"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"हेतू फिल्टर सत्यापित केले आहे किंवा नाही हे तपासण्यासाठी अॅपला अनुमती देते."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"हेतू फिल्टर सत्यापनकर्त्यावर प्रतिबद्ध व्हा"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"हेतू फिल्टर सत्यापनकर्त्यांच्या विनंत्या करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यकता नसावी."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"क्रमांक पोर्टवर प्रवेश करा"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API वापरून क्रमांक पोर्टवर प्रवेश करण्यास होल्डरला अनुमती देते."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"सामग्री प्रदात्यांवर बाह्यरित्या प्रवेश करेल"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"दिवस कमी करा"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"वर्ष वाढवा"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"वर्ष कमी करा"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"मागील महिना"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"पुढील महिना"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रद्द करा"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"हटवा"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"मिनिटे निवडा"</string>
<string name="select_day" msgid="7774759604701773332">"महिना आणि दिवस निवडा"</string>
<string name="select_year" msgid="7952052866994196170">"वर्ष निवडा"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> निवडले"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> हटविली"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"ही स्क्रीन अनपिन करण्यासाठी, एकाच वेळी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 132a7d4..5fc99e6 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Membenarkan apl mengambil gambar dan video menggunakan kamera. Kebenaran ini membenarkan apl untuk menggunakan kamera pada bila-bila masa tanpa pengesahan anda."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"lumpuhkan LED penunjuk penghantaran semasa kamera sedang digunakan"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Membenarkan aplikasi sistem yang diprapasang untuk melumpuhkan LED penunjuk penggunaan kamera."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"melumpuhkan tablet secara kekal"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"lumpuhkan TV secara kekal"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"lumpuhkan telefon secara kekal"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Membenarkan apl untuk mengesahkan bahawa pakej boleh dipasang."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ikat kepada pengesah pakej"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Membenarkan pemegang membuat permintaan pengesah pakej. Tidak sekali-kali diperlukan untuk apl normal."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"akses port bersiri"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Membenarkan pemegang mengakses port bersiri menggunakan API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"akses pembekal kandungan secara luaran"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Kurangkan hari"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tingkatkan tahun"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Kurangkan tahun"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Padam"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Pilih minit"</string>
<string name="select_day" msgid="7774759604701773332">"Pilih bulan dan hari"</string>
<string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> dipilih"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> dipadamkan"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Kerja <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk menyahsemat skrin ini, sentuh dan tahan Kembali serta Ikhtisar pada masa yang sama."</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 2e3f182..3470c1d 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"အပလီကေးရှင်းအား အလိုအလျောက် ဓာတ်ပုံရိုက်ခွင့်၊ ဗီဒီယို ရိုက်ကူးခွင့် ပြုပါ။ ဒီခွင့်ပြုချက်က အပလီကေးရှင်းကို အချိန်မရွေး ကင်မရာအား ခွင့်ပြုချက် မလိုအပ်ပဲ သုံးခွင့်ပြုပါသည်။"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ထုတ်လွှင့်မှုပြ အချက်ပေး မီးအား ကင်မရာ သုံးနေစဉ် ပိတ်ရန်"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ကြိုတင်သွင်းထားသော စစ်စတန် စနစ်တစ်ခုကို ကင်မရာ သုံးနေသော မီးအား ထိန်းချုပ်ခွင့်ပေးခြင်း"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"တက်ပလက်ကို အမြဲတမ်း အလုပ်မလုပ်ရန်ပိတ်ခြင်း"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"တီဗွီအား အပြီးပိတ်ရန်"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ဖုန်းကို အမြဲတမ်း အလုပ်မလုပ်ရန်ပိတ်ခြင်း"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"appအား အထုပ် တစ်ခု၏ မတည်ငြိမ်မှုကို စိစစ်ခွင့် ပြုသည်။"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"package အတည်ပြုခြင်းနှင့် ပူးပေါင်းရန်"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"စွဲကိုင်ထားသူအား အထုပ်များအား စိစစ်ရေး တောင်းဆိုချက်များကို ပြုလုပ်ခွင့် ပေးသည်။ သာမန် appများ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"လိုအပ်သည့်စစ်ထုတ်ခြင်းကို အတည်ပြုမည်"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"လိုအပ်သည့်စစ်ထုတ်ခြင်း အတည်ပြုပြီးခြင်း ရှိမရှိ အပ်ဖ်အား စစ်ဆေးခွင့်ပြုမည်။"</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"လိုအပ်သည့်စစ်ထုတ်ခြင်း အတည်ပြုကိရိယာဖြင့် ပေါင်းမည်"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"စွဲကိုင်ထားသူအား လိုအပ်အသည့်စစ်ထုတ်ခြင်း စိစစ်ရေး တောင်းဆိုချက်များကို ပြုလုပ်ခွင့် ပေးသည်။ သာမန် အပ်ဖ်များ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
<string name="permlab_serialPort" msgid="546083327654631076">"အစဥ်လိုက်ပို့များကို ဝင်ရောက်ချိတ်ဆက်ခြင်း"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager APIအားအသုံးပြုကာ ကိုင်ဆောင်သူကို စီရီယာပို့မျာကို ဝင်ရောက်အသုံးပြုခြင်းအား ခွင့်ပြုသည်။"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"အချက်အလက်များ ပံ့ပိုသူများအား အပြင်ဖက်မှ ရယူခြင်း"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ရက် လျှော့ရန်"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"ခုနှစ် တိုးရန်"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ခုနှစ် လျှော့ရန်"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ပြီးခဲ့သော လ"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"လာမည့် လ"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Altခလုတ်"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ပယ်ဖျက်ရန်ခလုတ်"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ဖျက်ရန်ခလုတ်"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"မိနစ်များ ရွေးပါ"</string>
<string name="select_day" msgid="7774759604701773332">"လ နှင့် ရက် ရွေးပါ"</string>
<string name="select_year" msgid="7952052866994196170">"ခုနှစ်ကို ရွေးပါ"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ခုရွေးချယ်ထားပြီး"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ကို ဖျက်ပြီးပါပြီ"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"အလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"ဒီမျက်နှာပြင် ပင်ထိုးမှုကို ဖြုတ်ရန်၊ နောက်သို့ နှင့် ခြုံကြည့်မှု ခလုတ်များကို တစ်ချိန်တည်း ထိကိုင်ထားပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index de3cae4..ccdf23a 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Appen tillates å ta bilder og filme med kameraet. Det betyr at appen kan bruke kameraet når som helst uten bekreftelse fra deg."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"deaktiver LED-lyset for indikering av overføring når kameraet er i bruk"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Tillater at forhåndsinnstallerte systemapper deaktiverer LED-indikatoren for kamerabruk."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"deaktivere nettbrettet permanent"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"deaktiver TV-en permanent"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"deaktivere telefonen permanent"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lar appen bekrefte om en pakke kan installeres."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en pakkeverifikator"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lar innehaveren sende forespørsler om pakkeverifikatorer. Skal aldri være nødvendig for normale apper."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"bekreft intensjonsfilter"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Gjør at appen kan sjekke om et bestemt intensjonsfilter er bekreftet eller ikke."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"knytt til en verifikator for intensjonsfiltre"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Lar innehaveren sende forespørsler om verifikatorer for intensjonsfiltre. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"bruke serieporter"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Gir innehaveren tilgang til serielle porter ved hjelp av SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"gå til innholdsleverandører eksternt"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reduser dager"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Øk år"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduser år"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Forrige måned"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Neste måned"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Avbryt"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Slett"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Angi minutter"</string>
<string name="select_day" msgid="7774759604701773332">"Velg måneden og dagen"</string>
<string name="select_year" msgid="7952052866994196170">"Velg året"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> er valgt"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> er slettet"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Jobb-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil avslutte én-appsmodusen for denne skjermen, trykker og holder du på Tilbake og Oversikt samtidig."</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 1b8180a..e1d9a21 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"अनुप्रयोगलाई क्यामेरासँग तस्बिर र भिडियोहरू लिन अनुमति दिन्छ। यस अनुमतिले अनुप्रयोगलाई तपाईंको पुष्टिकरण बिना कुनै पनि समयमा क्यामेरा प्रयोग गर्न स्वीकृति दिन्छ।"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"क्यामेरा प्रयोगमा हुँदा सूचक LED प्रसारण असक्षम गर्नुहोस्"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"पूर्व-स्थापित प्रणाली अनुप्रयोगलाई क्यामेरा उपयोग सूचक LED अक्षम गर्न अनुमति दिन्छ।"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"स्थायी रूपमा ट्याब्लेट असक्षम पार्नुहोस्"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"स्थायी रूपमा TV अक्षम गर्नुहोस्"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"फोनलाई स्थायी रूपमा असक्षम पार्नहोस्"</string>
@@ -753,7 +755,7 @@
<string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"औंला निकै छिटो सारियो। कृपया फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"औंला निकै ढिला सारियो। कृपया फेरि प्रयास गर्नुहोस्।"</string>
<string-array name="fingerprint_acquired_vendor">
- <item msgid="2892952818207766996">"उत्पादक-निर्दिष्ट अधिग्रहण त्रुटि सन्देश 0"</item>
+ <item msgid="2892952818207766996">"विक्रेता-निर्दिष्ट अधिग्रहण त्रुटि सन्देश 0"</item>
</string-array>
<string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"प्रसोधन गर्न असमर्थ। फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"हार्डवेयर उपलब्ध छैन।"</string>
@@ -761,7 +763,7 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"औँठाछापको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_error_vendor" msgid="3175724710791609491">"औँठाछापको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string>
<string-array name="fingerprint_error_vendor">
- <item msgid="5804600450373644614">"उत्पादक-निर्दिष्ट त्रुटि सन्देश।"</item>
+ <item msgid="5804600450373644614">"विक्रेता-निर्दिष्ट त्रुटि सन्देश।"</item>
</string-array>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"समीकरण सेटिङहरू पढ्नुहोस्"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"अनुप्रयोगलाई खाताको लागि सिङ्क सेटिङहरू पढ्न अनुमति दिन्छ। उदाहरणको लागि यसले व्यक्तिहरको अनुप्रयोग खातासँग सिङ्क भएको नभएको निर्धारण गर्न सक्दछ।"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"प्याकेज स्थापना योग्य छ कि भनेर रुजु गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"एउटा प्याकेज रुजुकर्तामा बाँध्नुहोस्"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"होल्डरलाई प्याकेज प्रमाणितकर्ताहरूको अनुरोधहरू बनाउन अनुमति दिन्छ। सामान्य अनुप्रयोगहरूलाई कहिले पनि आवश्यक नपर्न सक्दछ।"</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"उद्देश्य फिल्टर प्रमाणिकरण गर्नुहोस्"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"एउटा उद्देश्य फिल्टर प्रमाणित भएको छ वा छैन भन्ने जाँच्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"उद्देश्य फिल्टर प्रमाणिकरणकर्ता बाँध्नुहोस्"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"होल्डरलाई उद्देश्य फिल्टर प्रमाणिकरणकर्ताहरूका अनुरोध गर्न अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
<string name="permlab_serialPort" msgid="546083327654631076">"पहुँच सिरियल पोर्टहरू"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"होल्डरलाई SerialManager API प्रयोग गरेर सिरियल पोर्टहरू पहुँच गर्न अनुमति दिन्छ।"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"विषयसूची प्रदातालाई बाह्य रूपमा पहुँच गर्नुहोस्"</string>
@@ -1567,6 +1573,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"दिन घटाउनुहोस्"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"वर्ष बढाउनुहोस्"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"वर्ष घटाउनुहोस्"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"अघिल्लो महिना"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"अर्को महिना"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रद्द गर्नुहोस्"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"मेट्नुहोस्"</string>
@@ -1819,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"मिनेट चयन गर्नुहोस्"</string>
<string name="select_day" msgid="7774759604701773332">"महिना र दिन चयन गर्नुहोस्"</string>
<string name="select_year" msgid="7952052866994196170">"वर्ष चयन गर्नुहोस्"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> चयन गरियो"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> हटाइयो"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"यस पर्दालाई अनपिन गर्न एकै समय फिर्ता र सारांशलाई छोई पक्डिनुहोस्।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 425cb3a..6735e89 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Hiermee kan de app foto\'s en video\'s maken met de camera. Met deze toestemming kan de app de camera altijd gebruiken, zonder uw bevestiging."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"indicatielampje uitschakelen wanneer camera wordt gebruikt"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Staat toe dat een vooraf geïnstalleerde systeemapp het indicatielampje voor cameragebruik uitschakelt."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"tablet permanent uitschakelen"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"tv permanent uitschakelen"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"telefoon permanent uitschakelen"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Hiermee kan de app controleren of een pakket kan worden geïnstalleerd."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"koppelen aan pakketcontroleprogramma"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Hiermee kan de houder verzoeken indienen voor pakketcontroles. Nooit vereist voor normale apps."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"intentiefilter verifiëren"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Hiermee kan de app controleren of een intentiefilter is geverifieerd."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"verbinden aan intentiefilterverificatie"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Hiermee kan de houder verzoeken indienen voor verificatie van intentiefilters. Nooit vereist voor normale apps."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"toegang krijgen tot seriële poorten"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"De houder toestaan toegang tot seriële poorten te krijgen met de SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"externe toegang tot inhoudsproviders"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Lagere waarde voor dag"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Hogere waarde voor jaar"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Lagere waarde voor jaar"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Vorige maand"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Volgende maand"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuleren"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Minuten selecteren"</string>
<string name="select_day" msgid="7774759604701773332">"Maand en dag selecteren"</string>
<string name="select_year" msgid="7952052866994196170">"Jaar selecteren"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> geselecteerd"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> verwijderd"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Blijf \'Terug\' en \'Overzicht\' tegelijk aanraken om dit scherm los te maken."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b10ea37..2e41660 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -587,6 +587,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Pozwala aplikacji na robienie zdjęć i nagrywanie filmów przy użyciu aparatu. Aplikacja z tym uprawnieniem może użyć aparatu w dowolnym momencie bez Twojego potwierdzenia."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"wyłącz wskaźnik LED transmisji, gdy aparat jest w użyciu"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Zezwala wstępnie zainstalowanej aplikacji systemowej na wyłączenie wskaźnika LED użycia kamery."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trwałe wyłączenie tabletu"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"trwałe wyłączenie telewizora"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"wyłączenie telefonu na stałe"</string>
@@ -1138,6 +1140,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pozwala aplikacji na zweryfikowanie, czy pakiet można zainstalować."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"powiązanie z weryfikatorem pakietów"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pozwala na wysyłanie żądań weryfikacji pakietu. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"weryfikacja filtru intencji"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Zezwala aplikacji na sprawdzenie, czy filtr intencji został zweryfikowany."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"tworzenie powiązania z weryfikacją filtru intencji"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Zezwala na wysyłanie żądań weryfikacji filtrów intencji. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"dostęp do portów szeregowych"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Umożliwia posiadaczowi dostęp do portów szeregowych przy użyciu interfejsu API narzędzia SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"Dostęp do dostawców treści z zewnątrz"</string>
@@ -1577,6 +1583,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Zmień dzień na wcześniejszy"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Zmień rok na późniejszy"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Zmień rok na wcześniejszy"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Poprzedni miesiąc"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Następny miesiąc"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anuluj"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1831,7 +1839,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Wybierz minuty"</string>
<string name="select_day" msgid="7774759604701773332">"Wybierz miesiąc i dzień"</string>
<string name="select_year" msgid="7952052866994196170">"Wybierz rok"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Wybrałeś <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> usunięte"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (praca)"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Aby odpiąć ten ekran, naciśnij i przytrzymaj jednocześnie Wstecz i Przegląd."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4f1187c..f62e2fd 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que a aplicação tire fotografias e grave vídeos com a câmara. Esta autorização permite que a aplicação utilize a câmara sem a sua confirmação em qualquer altura."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desativar LED indicador de transmissão com a câmara em utilização"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que uma aplicação de sistema pré-instalada desative o LED indicador de utilização da câmara."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desativar tablet de forma permanente"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"desativar a TV permanentemente"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"desativar telefone de forma permanente"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que a aplicação verifique se um pacote é instalável."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacotes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite ao titular solicitar verificadores de pacotes. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"validar filtro de intenções"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite que uma aplicação verifique se um filtro de intenções está ou não validado."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"vincular a um verif. de filtros intenç."</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite ao titular solicitar verificadores de filtros de intenções. Nunca deve ser necessário para aplicações normais."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"aceder a portas série"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permite ao titular aceder a portas de série através da API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"aceder a fornecedores de conteúdos externamente"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Diminuir dia"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar ano"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Diminuir ano"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mês anterior"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mês seguinte"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Selecionar minutos"</string>
<string name="select_day" msgid="7774759604701773332">"Selecionar mês e dia"</string>
<string name="select_year" msgid="7952052866994196170">"Selecionar ano"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selecionado"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar este ecrã, toque sem soltar em Retroceder e Visão geral em simultâneo."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 6f68f06..e28c4d6 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desativar a transmissão do LED indicador quando a câmera estiver em uso"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que um app do sistema pré-instalado desative o LED indicador de uso da câmera."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desativar permanentemente o tablet"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"desativar TV permanentemente"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"desativar permanentemente o telefone"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que o app verifique se um pacote pode ser instalado."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacote"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que o titular solicite verificadores de pacote. Nunca deve ser necessário para apps normais."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificar filtro de intenção"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite que o app verifique se um filtro de intenção foi confirmado ou não."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"usar verificador de filtro de intenção"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite que o titular solicite verificadores de filtro de intenção. Nunca é necessário para apps normais."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"acessar portas seriais"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permite que o detentor tenha acesso a portas seriais usando a API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"acessar fornec. de conteúdo externamente"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Diminuir dia"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar ano"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Diminuir ano"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mês passado"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Próximo mês"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Excluir"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Selecione os minutos"</string>
<string name="select_day" msgid="7774759604701773332">"Selecione o mês e o dia"</string>
<string name="select_year" msgid="7952052866994196170">"Selecione o ano"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selecionado"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> excluído"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Trabalho: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Para liberar esta tela, toque e mantenha pressionados \"Voltar\" e \"Visão geral\" ao mesmo tempo."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index dc29c19..d62a4d7 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -586,6 +586,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite aplicației să realizeze fotografii și videoclipuri cu camera foto. Cu această permisiune aplicația utilizează camera foto oricând și fără confirmare."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"dezactivează ledul care indică când este utilizată camera foto"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite unei aplicații de sistem preinstalate să dezactiveze ledul care indică utilizarea camerei foto."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"dezactivarea permanentă a computerului tablet PC"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"dezactivează definitiv televizorul"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"dezactivare permanentă a telefonului"</string>
@@ -1137,6 +1139,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite aplicației să verifice dacă un pachet poate fi instalat."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"conectare la un verificator de pachete"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite proprietarului să efectueze solicitări pentru verificatori de pachete. Nu ar trebui să fie niciodată necesară pentru aplicațiile obişnuite."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifică filtrul de intenții"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite aplicației să afle dacă filtrul de intenții este verificat sau nu."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"se conectează la verificator de filtre de intenții"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite aplicației să efectueze solicitări pentru verificatorii filtrelor de intenții. Nu ar trebui să fie niciodată necesară pentru aplicațiile obişnuite."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"acces la porturi seriale"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Permite posesorului accesul la porturile serial utilizând API-ul SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accesaţi furniz. de conţin. din exterior"</string>
@@ -1569,6 +1575,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reduceţi valoarea pentru zi"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Creşteţi valoarea pentru an"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduceţi valoarea pentru an"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Luna trecută"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Luna viitoare"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anulați"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeţi"</string>
@@ -1822,7 +1830,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Selectați minutele"</string>
<string name="select_day" msgid="7774759604701773332">"Selectați luna și ziua"</string>
<string name="select_year" msgid="7952052866994196170">"Selectați anul"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selectat"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> a fost șters"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de serviciu"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Pentru a anula fixarea pe ecran, apăsați lung, simultan, pe Înapoi și pe Vizualizare generală."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index eb3b74a..d162624 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -587,6 +587,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Приложение сможет снимать фотографии и видеоролики с помощью камеры в любое время без вашего разрешения."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Отключать светодиодный индикатор во время использования камеры"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Предустановленное системное приложение сможет отключать светодиодный индикатор использования камеры."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"Выключение планшета"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"навсегда отключать телевизор"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"Отключение телефона"</string>
@@ -755,7 +757,7 @@
<string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"Вы слишком быстро убрали палец. Повторите попытку."</string>
<string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"Вы слишком долго удерживали палец. Повторите попытку."</string>
<string-array name="fingerprint_acquired_vendor">
- <item msgid="2892952818207766996">"Сообщение продавца об ошибке при сканировании отпечатка (0)"</item>
+ <item msgid="2892952818207766996">"Сообщение об ошибке при сканировании отпечатка (0)"</item>
</string-array>
<string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"Не удалось распознать отпечаток. Повторите попытку."</string>
<string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"Сканер недоступен."</string>
@@ -763,7 +765,7 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Превышено время ожидания. Повторите попытку."</string>
<string name="fingerprint_error_vendor" msgid="3175724710791609491">"Превышено время ожидания. Повторите попытку."</string>
<string-array name="fingerprint_error_vendor">
- <item msgid="5804600450373644614">"Сообщение продавца об ошибке."</item>
+ <item msgid="5804600450373644614">"Сообщение об ошибке."</item>
</string-array>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Просмотр настроек синхронизации"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Приложение сможет просматривать настройки синхронизации аккаунта, например определять, включена ли синхронизация для приложения \"Контакты\"."</string>
@@ -1138,6 +1140,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Приложение сможет проверять возможность установки пакетов."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Подключение к верификаторам пакетов"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Приложение сможет запрашивать проверку пакетов. Это разрешение не используется обычными приложениями."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"Доступ к последовательным портам"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Открыть владельцу доступ к последовательным портам с помощью SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"Доступ к контенту без приложения"</string>
@@ -1577,6 +1587,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"На день назад"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"На год вперед"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"На год назад"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Клавиша ALT"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Отмена"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Клавиша удаления"</string>
@@ -1831,7 +1845,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Выберите минуты"</string>
<string name="select_day" msgid="7774759604701773332">"Выберите месяц и число"</string>
<string name="select_year" msgid="7952052866994196170">"Выберите год"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Выбран элемент <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Цифра <xliff:g id="KEY">%1$s</xliff:g> удалена"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Рабочий <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Чтобы открепить экран, нажмите и удерживайте кнопки \"Назад\" и \"Обзор\" одновременно."</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 6d8b6df..54a74c6 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"කැමරාවෙන් පින්තූර ගැනීමට සහ වීඩියෝ කිරීමට යෙදුමට අවසර දෙන්න. මෙම අවසරය මඟින් ඔබගේ අනුදැනුමකින් තොරව ඕනෑම වේලාවකදී කැමරාව භාවිතා කිරීමට යෙදුමට අවසර දෙන්න."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"කැමරාව භාවිතයේදී LED දර්ශක සම්ප්රේෂණය අබල කරන්න"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"කැමරා භාවිතය පිළිබඳ LED දර්ශකය අක්රිය කිරීමට, කලින් පිහිටුවා ඇති පද්ධති යෙදුමට අවසර දෙන්න."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ටැබ්ලටය ස්ථිරවම අබල කිරීම"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"රූපවාහිනිය ස්ථිරවම අබල කරන්න"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"දුරකථනය ස්ථිරව අබල කිරීම"</string>
@@ -1138,6 +1140,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ස්ථාපිත කොට ඇති පැකේජයක් සත්යාපනයට යෙදුමට අවසර දෙන්න."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"පැකේජ සත්යාපකයක් වෙත බඳින්න"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"පැකේජ සත්යාපක ඉල්ලීම් වලට දරන්නාට ඉඩ ලබා දේ. සාමාන්ය යෙදුම් සඳහා කිසිසේත් අවශ්ය නොවේ."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"චේතනාන්විත පෙරහන සත්යාපනය කරන්න"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"චේතනාන්විත පෙරහනක් සත්යාපනය කර තිබේද නැද්ද යන්න පරීක්ෂා කිරීමට යෙදුමට ඉඩ දෙයි."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"චේතනාන්විත පෙරහන් සත්යාපනකාරකයක් වෙත බඳින්න"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"චේතනාන්විත පෙරහන් සත්යාපනකාරකවල ඉල්ලීම් සිදු කිරීමට දරන්නාට ඉඩ දෙයි. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවිය යුතුය."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"ශ්රේණිගත පොට ප්රවේශ කිරීම"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API භාවිතයෙන් අනුක්රම තොට වෙත ප්රවේශ වීමට රඳවනයට අවසර දෙන්න."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"බාහිර අන්තර්ගත සැපයුම්කරුවන් වෙත ප්රවේශය"</string>
@@ -1563,6 +1569,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"දවස අඩු කරන්න"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"වසර වැඩි කරන්න"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"වසර අඩු කරන්න"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"පෙර මාසය"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"ඊළඟ මාසය"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"අවලංගු කරන්න"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"මකන්න"</string>
@@ -1815,7 +1823,6 @@
<string name="select_minutes" msgid="3974345615920336087">"මිනිත්තු තෝරන්න"</string>
<string name="select_day" msgid="7774759604701773332">"මාසය සහ දිනය තෝරන්න"</string>
<string name="select_year" msgid="7952052866994196170">"වසර තෝරන්න"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> තෝරාගෙන ඇත"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> මකා දමන ලදි"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"මෙම තීරයේ ඇමුණුම ඉවත් කිරීමට, ආපසු සහ දළ විශ්ලේෂණය එකම වේලාවේ ස්පර්ශ කර අල්ලා සිටින්න."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 9059038..6964f65 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -587,6 +587,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Zakázať indikátor LED prenosu pri používaní fotoaparátu"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Umožňuje v predinštalovanej systémovej aplikácii zakázať indikátor LED používania fotoaparátu."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trvalé zakázanie tabletu"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"trvalé zakázanie televízora"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"trvalé vypnutie telefónu"</string>
@@ -1138,6 +1140,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikácii overiť, či je možné balík nainštalovať."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"naviazať na overovateľa balíka"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteľovi podávať žiadosti o overenie balíkov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"overiť filter intencií"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Umožňuje aplikácii overiť, či bol filter intencií overený."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"viazať na overenie filtra intencií"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Umožňuje držiteľovi podávať žiadosti o overenie filtra intencií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"prístup k sériovým portom"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Držiteľa oprávňuje na prístup k sériovým portom pomocou rozhrania API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"externý prístup k poskytovateľom obsahu"</string>
@@ -1577,6 +1583,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Ubrať deň"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Pridať rok"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Ubrať rok"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Predchádzajúci mesiac"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Nasledujúci mesiac"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Zrušiť"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Odstrániť"</string>
@@ -1831,7 +1839,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Vyberte minúty"</string>
<string name="select_day" msgid="7774759604701773332">"Vyberte mesiac a deň"</string>
<string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Bola vybratá položka <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Číslo <xliff:g id="KEY">%1$s</xliff:g> bolo odstránené"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Práca – <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Ak chcete uvoľniť túto obrazovku, súčasne klepnite na tlačidlá Späť a Prehľad a podržte ich."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index c5f78b1..4e779f3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -587,6 +587,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogoča fotografiranje in snemanje videoposnetkov s kamero. S tem dovoljenjem lahko aplikacija kadar koli uporablja kamero brez vaše potrditve."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"onemogoči LED-indikator prenašanja, ko je fotoaparat v uporabi"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Dovoli že nameščeni sistemski aplikaciji, da onemogoči LED-indikator uporabe fotoaparata."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trajno onemogočenje tabličnega računalnika"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"trajno onemogočanje televizorja"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"trajno onemogočenje telefona"</string>
@@ -1138,6 +1140,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Aplikaciji omogoča, da preveri, ali je paket mogoče namestiti."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"poveži s preverjanjem paketov"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Imetniku omogoča zahtevanje preverjanja paketov. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"preverjanje filtra namena"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Aplikaciji omogoča, da preveri, ali je filter namena preverjen ali ne."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"povez. s preverjevalnikom filtra namena"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Imetniku omogoča zahtevanje preverjevalnikov filtra namena. Tega se ne sme nikoli uporabiti za navadne aplikacije."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"dostop do serijskih vrat"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Imetniku omogoča, da z API-jem za SerialManager dostopa do serijskih vrat."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"zunanji dostop do ponudnikov vsebine"</string>
@@ -1577,6 +1583,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Zmanjšanje vrednosti za dan"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Povečanje vrednosti za leto"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Zmanjšanje vrednosti za leto"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Prejšnji mesec"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Naslednji mesec"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Tipka Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Prekliči"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Tipka Delete"</string>
@@ -1831,7 +1839,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Izberite minute"</string>
<string name="select_day" msgid="7774759604701773332">"Izberite mesec in dan"</string>
<string name="select_year" msgid="7952052866994196170">"Izberite leto"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Izbrano: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Številka <xliff:g id="KEY">%1$s</xliff:g> je izbrisana"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za delo"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Če želite odpeti ta zaslon, se hkrati dotaknite tipk Nazaj in Pregled ter ju pridržite."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 189113a..72da7fc 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -586,6 +586,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Дозвољава апликацији да снима слике и видео снимке камером. Ова дозвола омогућава апликацији да у било ком тренутку користи камеру без ваше потврде."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"онемогући пренос LED осветљења индикатора док се камера користи"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Дозвољава унапред инсталираној системској апликацији да онемогући LED осветљење индикатора за коришћење камере."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"трајно онемогућавање таблета"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"трајно онемогућавање ТВ-а"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"трајно онемогућавање телефона"</string>
@@ -1137,6 +1139,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозвољава апликацији да верификује да ли је пакет могуће инсталирати."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обавезивање на верификатор пакета"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Омогућава да власник упућује захтеве верификаторима пакета. Уобичајене апликације никада не би требало да је користе."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"верификација intent филтера"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Дозвољава апликацији са провери да ли је intent филтер верификован."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"повезив. са верификатором intent филтера"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Дозвољава власнику да упућује захтеве верификаторима intent филтера. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"приступ серијским портовима"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Омогућава власнику да приступи серијским портовима помоћу SerialManager API-ја."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"приступ добављачима садржаја споља"</string>
@@ -1569,6 +1575,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Смањивање дана"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Повећавање године"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Смањивање године"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Претходни месец"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Следећи месец"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Откажи"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Избриши"</string>
@@ -1822,7 +1830,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Изаберите минуте"</string>
<string name="select_day" msgid="7774759604701773332">"Изаберите месец и дан"</string>
<string name="select_year" msgid="7952052866994196170">"Изаберите годину"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Изабрали сте <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Избрисали сте <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> на послу"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Да бисте откачили овај екран, истовремено додирните и задржите Назад и Преглед."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3973636..9ca2dc8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Tillåter att appen tar bilder och spelar in videor med kameran. Med den här behörigheten tillåts appen att använda kameran när som helst utan ditt godkännande."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"inaktivera LED-sändningsindikator när kameran används"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Tillåter att en förinstallerad systemapp inaktiverar LED-indikatorn för kameranvändning."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"inaktivera surfplattan permanent"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"inaktivera tv:n permanent"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"inaktivera telefonen permanent"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillåter att appen kontrollerar om ett paket går att installera."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"binda till en paketverifierare"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillåter att innehavaren skickar förfrågningar till paketverifierare. Det ska inte behövas för vanliga appar."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifiera intent-filter"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Tillåter att appen kontrollerar om ett intent-filter har verifierats eller inte."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"binda till en intent-filterverifierare"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Tillåter att innehavaren skickar begäranden till intent-filterverifierare. Behövs inte för vanliga appar."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"åtkomst till serieportar"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Innebär att innehavaren får åtkomst till serieportar med programmeringsgränssnittet för SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"komma åt innehållsleverantörer externt"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Minska dagar"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Öka år"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Minska år"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Föregående månad"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Nästa månad"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Avbryt"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Välj minuter"</string>
<string name="select_day" msgid="7774759604701773332">"Välj månad och dag"</string>
<string name="select_year" msgid="7952052866994196170">"Välj år"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> har markerats"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> har tagits bort"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> för arbetet"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Om du vill lossa skärmen trycker du länge på Tillbaka och Översikt samtidigt."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0f1d7ae..e48fa23 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Inaruhusu programu kupiga picha na video kwa kamera. Kibali hiki kinaruhusu programu kutumia kamera kwa wakati wowote bila uthibitisho wako."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"zima LED ya kisambaza kiashirio wakati kamera inatumika"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Huruhusu mfumo wa programu iliyosakinishwa awali kuzima kamera isitumie kiashirio cha LED."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"zima kompyuta ndogo kabisa"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"zima runinga kabisa"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"simu iliyolemazwa kabisa"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Inaruhusu programu kuthibitisha kuwa furushi linaweza kusakinishwa."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Funga kwa kithibitishaji cha furushi"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Inaruhusu mmiliki kutuma maombi ya vibainishi furushi. Kamwe hazitahitajika kwa programu za kawaida."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"thibitisha kichujio cha kutoa maagizo"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Inaruhusu programu kukagua ikiwa kuchujio cha kutoa maagizo kimethibitishwa au bado."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"funga kwenye kithibitishaji cha kichujio cha kutoa maagizo."</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Inaruhusu mmiliki kutuma maombi ya vithibitishaji vya kichujio cha kutoa maagizo. Haviwezi kuhitajika katika programu za kawaida."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"kituo tambulishi cha ufikivu"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Inaruhusu mmiliki kufikia vituo tambulishi kwa kutumia KisimamiziTambulishi cha API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"fikia watoa huduma nje"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Punguza siku"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Ongeza mwaka"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Punguza mwaka"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mwezi uliopita"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mwezi ujao"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ghairi"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Futa"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Chagua dakika"</string>
<string name="select_day" msgid="7774759604701773332">"Chagua mwezi na siku"</string>
<string name="select_year" msgid="7952052866994196170">"Chagua mwaka"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> kimechaguliwa"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> kimefutwa"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Ya kazini <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Ili ubanue skrini hii, gusa na ushikilie Nyuma na Muhtasari kwa wakati mmoja."</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index c473bc1..c059b32 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"கேமரா மூலமாகப் படங்களையும், வீடியோக்களையும் எடுக்க பயன்பாட்டை அனுமதிக்கிறது. உங்கள் உறுதிப்படுத்தல் இன்றி கேமராவை எந்நேரத்திலும் பயன்படுத்தப் பயன்பாட்டை இது அனுமதிக்கிறது."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"கேமரா பயன்பாட்டில் இருக்கும்போது டிரான்ஸ்மிட் இன்டிகேட்டர் LED ஐ முடக்குதல்"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"இன்டிகேட்டர் LED ஐ கேமரா பயன்படுத்துவதை முடக்க, முன்நிறுவப்பட்ட அமைப்பு பயன்பாட்டை அனுமதிக்கிறது."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"டேப்லெட்டை நிரந்தரமாக முடக்குதல்"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"டிவியை நிரந்தரமாக முடக்குதல்"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"தொலைபேசியை நிரந்தரமாக முடக்குதல்"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"பேக்கேஜ் நிறுவுவதற்கு ஏற்றதா என்பதைச் சரிபார்க்க, பயன்பாட்டை அனுமதிக்கிறது."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"தொகுப்பு சரிபார்ப்பானுடன் இணைத்தல்"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"தொகுப்பைச் சரிபார்ப்பிற்கான கோரிக்கைகளை உருவாக்க, ஹோல்டரை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"இன்டென்ட் வடிப்பானைச் சரிபார்த்தல்"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"இன்டென்ட் வடிப்பான் சரிபார்க்கப்பட்டதா அல்லது இல்லையா என்பதைச் சோதிக்க, பயன்பாட்டை அனுமதிக்கும்."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"இன்டென்ட் வடிப்பான் சரிபார்ப்பியுடன் இணைத்தல்"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"இன்டென்ட் வடிப்பான் சரிபார்ப்பிகளின் கோரிக்கைகளை உருவாக்க ஹோல்டரை அனுமதிக்கும். சாதாரணப் பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"தொடர் போர்ட்களின் அணுகல்"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API ஐப் பயன்படுத்தி தொடர் போர்ட்களை அணுக ஹோல்டரை அனுமதிக்கிறது."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"வெளிப்புறமாக வழங்கப்படும் உள்ளடக்கத்திற்கான அணுகல்"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"நாளினைக் குறை"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"வருடத்தை அதிகரி"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"வருடத்தைக் குறை"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"முந்தைய மாதம்"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"அடுத்த மாதம்"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ரத்துசெய்"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"நீக்கு"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"நிமிடத்தைத் தேர்ந்தெடுக்கவும்"</string>
<string name="select_day" msgid="7774759604701773332">"மாதம் மற்றும் தேதியைத் தேர்ந்தெடுக்கவும்"</string>
<string name="select_year" msgid="7952052866994196170">"ஆண்டைத் தேர்ந்தெடுக்கவும்"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> தேர்ந்தெடுக்கப்பட்டது"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> நீக்கப்பட்டது"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"பணியிடம் <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"இந்தத் திரையை விலக்க, பின் மற்றும் மேலோட்டப் பார்வையை ஒரே நேரத்தில் தொட்டுப் பிடித்திருக்கவும்."</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 5bc59c3..f7b661e 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"కెమెరాతో చిత్రాలు మరియు వీడియోలను తీయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఈ అనుమతి మీ నిర్ధారణ లేకుండానే ఎప్పుడైనా కెమెరాను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"కెమెరా ఉపయోగంలో ఉన్నప్పుడు ప్రసరణ సూచీ LEDని నిలిపివేయడం"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"కెమెరా వినియోగ సూచీ LEDని నిలిపివేయడానికి ముందే ఇన్స్టాల్ చేయబడిన సిస్టమ్ అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"టాబ్లెట్ను శాశ్వతంగా నిలిపివేయడం"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"టీవీని శాశ్వతంగా నిలిపివేయడం"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ఫోన్ను శాశ్వతంగా నిలిపివేయడం"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ప్యాకేజీ ఇన్స్టాల్ చేయవచ్చని ధృవీకరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ప్యాకేజీ తనిఖీదారుకు అనుబంధించడం"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ప్యాకేజీ తనిఖీదారుల యొక్క అభ్యర్థనలు చేయడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ఉద్దేశిత ఫిల్టర్ను ధృవీకరించడం"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ఉద్దేశిత ఫిల్టర్ ధృవీకరించబడిందో లేదో తనిఖీ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ఉద్దేశిత ఫిల్టర్ వెరిఫైయర్కి నిర్బంధించడం"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ఉద్దేశిత ఫిల్టర్ వెరిఫైయర్ల అభ్యర్థనలు చేయడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"శ్రేణి పోర్ట్లను ప్రాప్యత చేయడం"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"శ్రేణి నిర్వాహికి APIని ఉపయోగించి శ్రేణి పోర్ట్లను ప్రాప్యత చేయడానికి హోల్డర్ను అనుమతిస్తుంది."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"కంటెంట్ ప్రదాతలను బాహ్యంగా ప్రాప్యత చేయడం"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"రోజును తగ్గించండి"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"సంవత్సరాన్ని పెంచండి"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"సంవత్సరాన్ని తగ్గించండి"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"మునుపటి నెల"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"తదుపరి నెల"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"రద్దు చేయి"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"తొలగించు"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"నిమిషాలను ఎంచుకోండి"</string>
<string name="select_day" msgid="7774759604701773332">"నెల మరియు రోజును ఎంచుకోండి"</string>
<string name="select_year" msgid="7952052866994196170">"సంవత్సరాన్ని ఎంచుకోండి"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ఎంచుకోబడింది"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> తొలగించబడింది"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"ఈ స్క్రీన్ను అన్పిన్ చేయడానికి, వెనుకకు మరియు అవలోకనం బటన్లను ఒకేసారి నొక్కి, ఉంచండి."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index adbe8c9..e42017b 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"อนุญาตให้แอปพลิเคชันถ่ายภาพและวิดีโอด้วยกล้องถ่ายรูปนี้ การอนุญาตนี้จะทำให้แอปพลิเคชันสามารถใช้กล้องถ่ายรูปได้ทุกเมื่อโดยไม่ต้องรอการยืนยันจากคุณ"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ปิดไฟสัญญาณ LED เมื่อใช้งานกล้อง"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"อนุญาตให้แอปพลิเคชันระบบที่ติดตั้งล่วงหน้าปิดไฟสัญญาณ LED ของกล้อง"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ปิดการใช้งานแท็บเล็ตอย่างถาวร"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"ปิดใช้ทีวีถาวร"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ปิดการใช้งานโทรศัพท์ถาวร"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพ็กเกจสามารถติดตั้งได้หรือไม่"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพ็กเกจ"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพ็กเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ยืนยันตัวกรองความตั้งใจ"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"อนุญาตให้แอปตรวจสอบว่ามีการยืนยันตัวกรองความตั้งใจหรือไม่"</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"เชื่อมโยงกับการยืนยันตัวกรองความตั้งใจ"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"อนุญาตให้แอปส่งคำขอการยืนยันตัวกรองความตั้งใจ แอปทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"เข้าถึงผู้ให้บริการเนื้อหาจากภายนอก"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ลดวัน"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"เพิ่มปี"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ลดปี"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"เดือนที่แล้ว"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"เดือนหน้า"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ยกเลิก"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ลบ"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"เลือกนาที"</string>
<string name="select_day" msgid="7774759604701773332">"เลือกเดือนและวัน"</string>
<string name="select_year" msgid="7952052866994196170">"เลือกปี"</string>
- <string name="item_is_selected" msgid="949687401682476608">"เลือก <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"ลบ <xliff:g id="KEY">%1$s</xliff:g> แล้ว"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g>ที่ทำงาน"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"หากต้องการเลิกตรึงหน้าจอนี้ แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้พร้อมกัน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 978939b..6dccdec 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Pinapayagan ang app na kumuha ng mga larawan at video gamit ang camera. Pinapayagan ng pahintulot na ito ang app na gamitin ang camera anumang oras nang wala ng iyong kumpirmasyon."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"i-disable ang LED na tagapagpahiwatig kapag ginagamit ang camera"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Pinapayagan ang isang paunang na-install na application ng system na i-disable ang LED na tagapagpahiwatig ng paggamit sa camera."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"permanenteng huwag paganahin ang tablet"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"permanenteng i-disable ang TV"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"permanenteng huwag paganahin ang telepono"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pinapayagan ang app na i-verify kung ang isang package ay nai-install."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sumailalim sa taga-verify ng package"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pinapayagan ang may-ari na gumawa ng mga kahilingan ng mga taga-verify ng package. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"i-verify ang intent filter"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Nagbibigay-daan sa app na suriin kung na-verify o hindi ang isang intent filter."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"isailalim sa verifier ng intent filter"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Nagbibigay-daan sa may-ari na gumawa ng mga kahilingan ng mga verifier ng intent filter. Hindi kailanman dapat kailanganin para sa mga normal na app."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"mag-access sa mga serial port"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Binibigyang-daan ang may-ari na mag-access ng mga serial port gamit ang SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"panlabas na mag-access ng mga provider ng nilalaman"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Bawasan ang araw"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Dagdagdan ang taon"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Bawasan ang taon"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Nakaraang buwan"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Susunod na buwan"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Kanselahin"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Tanggalin"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Pumili ng mga minuto"</string>
<string name="select_day" msgid="7774759604701773332">"Pumili ng buwan at araw"</string>
<string name="select_year" msgid="7952052866994196170">"Pumili ng taon"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Napili ang <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Tinanggal ang <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Bumalik at Overview nang sabay-sabay."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 6c80b92..ae34ae5 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Uygulamaya kamerayla fotoğraf ve video çekme izni verir. Bu izin, uygulamanın sizin onayınız olmadan istediği zaman kamerayı kullanmasına olanak sağlar."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Kamera kullanımda iken iletim göstergesi LED\'ini devre dışı bırak"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Önceden yüklenmiş bir sistem uygulamasına kamera kullanım göstergesi LED\'ini devre dışı bırakma izni verir."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"tableti kalıcı olarak devre dışı bırak"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"TV\'yi kalıcı olarak devre dışı bırakma"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"telefonu tamamen devre dışı bırak"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Uygulamaya, bir paketin yüklenebilir olduğunu doğrulama izni verir."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"paket doğrulayıcıya bağlan"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cihazın sahibine, paket doğrulayıcıları için istek yapma izni verir. Normal uygulamalar için gerekli olmaz."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"seri bağlantı noktalarına eriş"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"İzin sahibinin, SerialManager API\'sını kullanarak seri bağlantı noktalarına erişmesine olanak sağlar."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"içerik sağlayıcılara harici olarak eriş"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Günü azalt"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Yılı artır"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Yılı azalt"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"İptal"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Sil"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Dakikayı seçin"</string>
<string name="select_day" msgid="7774759604701773332">"Ayı ve günü seçin"</string>
<string name="select_year" msgid="7952052866994196170">"Yılı seçin"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seçildi"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> silindi"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (İş)"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Bu ekranın sabitlemesini kaldırmak için Geri ve Genel Bakış\'a aynı anda dokunup basılı tutun."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 07eb0e8..67e47e6 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -587,6 +587,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Дозволяє програмі фотографувати та знімати відео за допомогою камери. Такий дозвіл дає програмі змогу будь-коли використовувати камеру без вашого підтвердження."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"вимикати світлодіодний індикатор передавання, коли використовується камера"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Дозволяє попередньо встановленій системній програмі вимикати світлодіодний індикатор використання камери."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"остаточно вимкнути пристрій"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"назавжди вимкнути телевізор"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"остаточно вимкнути телефон"</string>
@@ -1138,6 +1140,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозволяє програмі перевіряти можливість встановлення пакета."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"прив’язуватися до програми перевірки пакетів"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дозволяє власникові робити запити на програми перевірки пакетів. Ніколи не застосовується для звичайних програм."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"перевірка фільтра команд"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Додаток може визначати, чи перевірено фільтр команд."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"пов’язувати з перевіркою фільтра команд"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Власник може перевірити фільтр команд. Ніколи не застосовується для звичайних додатків."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"отримувати доступ до послідовних портів"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Дозволяє власнику отримувати доступ до послідовних портів за допомогою API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"отримув. ззовні доступ до постач. вмісту"</string>
@@ -1577,6 +1583,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"На день назад"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"На рік уперед"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"На рік назад"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Попередній місяць"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Наступний місяць"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Скасувати"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1831,7 +1839,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Виберіть хвилини"</string>
<string name="select_day" msgid="7774759604701773332">"Виберіть місяць і день"</string>
<string name="select_year" msgid="7952052866994196170">"Виберіть рік"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Вибрано: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> видалено"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Робоча <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Щоб відкріпити екран, одночасно натисніть і утримуйте кнопки \"Назад\" та \"Огляд\"."</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index a5e139d..d787b7388 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ایپ کو کیمرے سے تصویریں لینے اور ویڈیوز بنانے کی اجازت دیتا ہے۔ یہ اجازت ایپ کو آپ کی تصدیق کے بغیر کسی بھی وقت کیمرا استعمال کرنے کی اجازت دیتی ہے۔"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"کیمرا استعمال میں ہونے پر ٹرانسمیٹ انڈیکیٹر LED کو غیر فعال کریں"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"پہلے سے انسٹال کردہ کسی سسٹم ایپلیکیشن کو کیمرا کے استعمال کے انڈیکیٹر LED کو غیر فعال کرنے کی اجازت دیتا ہے۔"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ٹیبلیٹ کو مستقل طور پر غیر فعال کریں"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"مستقل طور پر TV غیر فعال کریں"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"فون کو مستقل طور پر غیر فعال کریں"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ایپ کو اس بات کی توثیق کرنے کی اجازت دیتا ہے کہ پیکج انسٹال کرنے قابل ہے۔"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"پیکج کے ایک توثیق کار کے پابند بنیں"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"حامل کو پیکیج کے توثیق کاروں کی درخواستیں کرنے دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"سیریل پورٹس تک رسائی حاصل کریں"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API کا استعمال کرکے حامل کو سیریل پورٹز تک رسائی دیتا ہے۔"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"مواد فراہم کنندگان تک خارجی رسائی حاصل کریں"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"دن گھٹائیں"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"سال بڑھائیں"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"سال گھٹائیں"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"منسوخ کریں"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"حذف کریں"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"منٹ منتخب کریں"</string>
<string name="select_day" msgid="7774759604701773332">"ماہ اور دن منتخب کریں"</string>
<string name="select_year" msgid="7952052866994196170">"سال منتخب کریں"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> کو منتخب کیا گیا"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> کو حذف کر دیا گیا"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"دفتر <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"اس اسکرین سے پن ہٹانے کیلئے، واپس جائیں اور مجموعی جائزہ کو ایک ساتھ ٹچ کریں اور دبا کر رکھیں۔"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index f0a6abb..e79f52d 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ilovaga kameradan foydalanib rasm va videoga olishga ruxsat beradi. Bu ruxsat ilovaga sizdan tasdiqlashni so‘ramasdan kameradan foydalanishga imkon beradi."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"LED ko‘rsatkichni kamera faolligida boshqarish imkoniyatini o‘chirish"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Zavodda o‘rnatilgan tizim dasturiga kamerani o‘chirish uchun LED ko‘rsatkichidan foydalanish imkonini beradi."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"doimo planshetni o‘chirish"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"televizorni butunlay o‘chirib qo‘yish"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"doimo telefonni o‘chirish"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ilova paketlarni o‘rnatish imkoniyatini tekshirishi mumkin."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"paketni tekshirgichga bog‘lash"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ilova paketlarni tekshirishni talab qilishi mumkin. Oddiy ilovalar uchun talab qilinmaydi."</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"serial portlarga kirish"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Foydalanuvchiga SerialManager API’dan foydalanib, serial portlarga kirishga ruxsat beradi."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"kontent provayderiga tashqi ruxsat"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Kunni kamaytirish"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Yilni ko‘paytirish"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Yilni kamaytirish"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Bekor qilish"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"O‘chirish"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Daqiqalarni tanlash"</string>
<string name="select_day" msgid="7774759604701773332">"Oy va kunni tanlash"</string>
<string name="select_year" msgid="7952052866994196170">"Yilni tanlash"</string>
- <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> tanlandi"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> o‘chirildi"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Ish <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Ushbu ekrandan chiqish uchun “Orqaga” va “Umumiy nazar” tugmalarini bir vaqtda bosib turing."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 73c2b67..07f291a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Cho phép ứng dụng chụp ảnh và quay video bằng máy ảnh. Quyền này cho phép ứng dụng sử dụng máy ảnh bất kỳ lúc nào mà không cần sự xác nhận của bạn."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"vô hiệu hóa tính năng phát đèn LED chỉ báo khi máy ảnh đang được sử dụng"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Cho phép cài đặt trước ứng dụng hệ thống để vô hiệu hóa việc máy ảnh sử dụng đèn LED chỉ báo."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"vô hiệu hóa vĩnh viễn máy tính bảng"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"tắt vĩnh viễn TV"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"vĩnh viễn vô hiệu hóa điện thoại"</string>
@@ -753,7 +755,7 @@
<string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"Ngón tay đã di chuyển quá nhanh. Vui lòng thử lại."</string>
<string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"Ngón tay đã di chuyển quá chậm. Vui lòng thử lại."</string>
<string-array name="fingerprint_acquired_vendor">
- <item msgid="2892952818207766996">"Thông báo lỗi lấy vân tay cho người bán cụ thể 0"</item>
+ <item msgid="2892952818207766996">"Thông báo lỗi lấy vân tay từ người bán cụ thể 0"</item>
</string-array>
<string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"Không thể xử lý. Hãy thử lại."</string>
<string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"Phần cứng không có sẵn."</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Cho phép ứng dụng xác minh gói có thể cài đặt."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"liên kết với trình xác minh gói"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cho phép chủ sở hữu yêu cầu trình xác minh gói. Không cần thiết cho các ứng dụng thông thường."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"xác minh bộ lọc theo mục đích"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Cho phép ứng dụng kiểm tra xem bộ lọc theo mục đích đã được xác minh hay chưa."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"liên kết với trình xác minh bộ lọc theo mục đích"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Cho phép chủ sở hữu yêu cầu trình xác minh bộ lọc theo mục đích. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"truy cập cổng nối tiếp"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Cho phép chủ sở hữu truy cập cổng nối tiếp sử dụng API SerialManager."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"truy cập vào nhà cung cấp nội dung từ bên ngoài"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Giảm ngày"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tăng năm"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Giảm năm"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Tháng trước"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Tháng sau"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Hủy"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Xóa"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Chọn phút"</string>
<string name="select_day" msgid="7774759604701773332">"Chọn tháng và ngày"</string>
<string name="select_year" msgid="7952052866994196170">"Chọn năm"</string>
- <string name="item_is_selected" msgid="949687401682476608">"Đã chọn <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"Đã xóa <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> làm việc"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Để bỏ khóa màn hình này, chạm và giữ Quay lại và Tổng quan cùng lúc."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 63dd5c7..e932190 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"允许该应用使用相机拍摄照片和视频。此权限可让该应用随时使用相机,而无需您的确认。"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"在相机使用过程中停用传输指示灯 LED"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"允许预装的系统应用禁止相机使用指示灯 LED。"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"永久停用平板电脑"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"永久停用电视"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"永久停用手机"</string>
@@ -761,7 +763,7 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指纹录入操作超时,请重试。"</string>
<string name="fingerprint_error_vendor" msgid="3175724710791609491">"指纹录入操作超时,请重试。"</string>
<string-array name="fingerprint_error_vendor">
- <item msgid="5804600450373644614">"针对供应商的错误消息"</item>
+ <item msgid="5804600450373644614">"针对供应商的错误消息。"</item>
</string-array>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"读取同步设置"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允许该应用读取某个帐户的同步设置。例如,此权限可确定“联系人”应用是否与某个帐户同步。"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允许应用验证软件包是否可安装。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"绑定到软件包验证程序"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允许应用申请使用软件包验证程序。普通应用绝不需要此权限。"</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"访问串行端口"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"允许应用通过SerialManager API使用串行端口。"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"从外部访问内容提供程序"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"减小日期值"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"增大年份值"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"减小年份值"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"选择分钟"</string>
<string name="select_day" msgid="7774759604701773332">"选择月份和日期"</string>
<string name="select_year" msgid="7952052866994196170">"选择年份"</string>
- <string name="item_is_selected" msgid="949687401682476608">"已选择<xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"已删除<xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"要取消固定此屏幕,请同时触摸并按住“返回”和“概览”按钮。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 4956a88..5454bd2 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限允許應用程式隨時使用相機,而不需經您確認。"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"使用相機時停用傳輸指示燈"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"允許預先安裝的系統應用程式停用相機指示燈。"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"永久停用平板電腦"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"永遠停用電視"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"永久停用手機"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允許應用程式驗證套件是否可安裝。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"繫結至套件驗證程序"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允許應用程式要求驗證套件 (不建議一般應用程式使用)。"</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"接入串列通訊埠"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"允許應用程式使用 SerialManager API 接入串列通訊埠。"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"從外部存取內容供應商"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"減少日數"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"增加年數"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"減少年數"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"刪除"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"選取分鐘"</string>
<string name="select_day" msgid="7774759604701773332">"選取月份和日期"</string>
<string name="select_year" msgid="7952052866994196170">"選取年份"</string>
- <string name="item_is_selected" msgid="949687401682476608">"已選取<xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> 已刪除"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住 [返回] 和 [概覽]。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 98c1cd2..7e7b0d3 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限可讓應用程式隨時使用相機,而不需請求您進行確認。"</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"使用攝影機時停用傳輸指示器 LED"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"允許預先安裝的系統應用程式停用攝影機指示器 LED。"</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"永久停用平板電腦"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"永久停用電視"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"永久停用電話"</string>
@@ -753,7 +755,7 @@
<string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"手指移動速度過快,請再試一次。"</string>
<string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"手指移動速度過慢,請再試一次。"</string>
<string-array name="fingerprint_acquired_vendor">
- <item msgid="2892952818207766996">"供應商專用的指紋擷取錯誤訊息 0"</item>
+ <item msgid="2892952818207766996">"供應商自訂的指紋擷取錯誤訊息 0"</item>
</string-array>
<string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"無法辨識指紋,請再試一次。"</string>
<string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"硬體無法使用。"</string>
@@ -761,7 +763,7 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋處理作業逾時,請再試一次。"</string>
<string name="fingerprint_error_vendor" msgid="3175724710791609491">"指紋處理作業逾時,請再試一次。"</string>
<string-array name="fingerprint_error_vendor">
- <item msgid="5804600450373644614">"供應商專用的錯誤訊息。"</item>
+ <item msgid="5804600450373644614">"供應商自訂的錯誤訊息。"</item>
</string-array>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"讀取同步處理設定"</string>
<string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允許應用程式讀取帳戶的同步處理設定,例如判斷「使用者」應用程式是否和某個帳戶進行同步處理。"</string>
@@ -1136,6 +1138,14 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允許應用程式驗證是否可安裝特定套件。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"繫結至套件驗證程序"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允許應用程式要求驗證套件 (一般應用程式不需使用)。"</string>
+ <!-- no translation found for permlab_intentFilterVerificationAgent (1135788294400437497) -->
+ <skip />
+ <!-- no translation found for permdesc_intentFilterVerificationAgent (5853902808424716312) -->
+ <skip />
+ <!-- no translation found for permlab_bindIntentFilterVerifier (8567268159430779210) -->
+ <skip />
+ <!-- no translation found for permdesc_bindIntentFilterVerifier (681128728719578778) -->
+ <skip />
<string name="permlab_serialPort" msgid="546083327654631076">"存取序列埠"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"允許應用程式使用 SerialManager API 存取序列埠。"</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"從外部存取內容供應端"</string>
@@ -1561,6 +1571,10 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"減少日數"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"增加年數"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"減少年數"</string>
+ <!-- no translation found for date_picker_prev_month_button (2858244643992056505) -->
+ <skip />
+ <!-- no translation found for date_picker_next_month_button (5559507736887605055) -->
+ <skip />
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt 鍵"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete 鍵"</string>
@@ -1813,7 +1827,6 @@
<string name="select_minutes" msgid="3974345615920336087">"選取分鐘數"</string>
<string name="select_day" msgid="7774759604701773332">"選取月份和日期"</string>
<string name="select_year" msgid="7952052866994196170">"選取年份"</string>
- <string name="item_is_selected" msgid="949687401682476608">"已選取 <xliff:g id="ITEM">%1$s</xliff:g>"</string>
<string name="deleted_key" msgid="7659477886625566590">"已刪除 <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住返回按鈕和總覽按鈕。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 1833ece..4abcfea 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -585,6 +585,8 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ivumela uhlelo lokusebenza ukuthatha izithombe namavidiyo ngekhamera. Le mvume ivumela uhlelo lokusebenza ukusebenzisa ikhamera nganoma isiphi isikhathi ngaphandle kwemvume yakho."</string>
<string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"khubaza i-LED yesikhombi sokudlulisa uma ikhamera isebenza"</string>
<string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Ivumela isistimu efakwe ngaphambili yohlelo lokusebenza ukuze ikhubaze i-LED yesikhombi sokusetshenziswa kwekhamera."</string>
+ <!-- no translation found for permdesc_cameraSendSystemEvent (8642231538552298107) -->
+ <skip />
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"vimbela ngokuphelele ithebhulethi"</string>
<string name="permlab_brick" product="tv" msgid="4912674222121249410">"khubaza unaphakade i-TV"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"ngokwaphakade vimbela ifoni"</string>
@@ -1136,6 +1138,10 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ivumela ukuthi isisetshenziswa siqinisekise ukuthi ngabe iphakheji iyafakeka."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bopha okokuqinisekisa iphakheji"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ivumela umnikazi ukuthi enze izicelo zezinsiza eziqinisekisa iphakheji. Akumele kudingeke ekusetshenzisweni okujwayelekile."</string>
+ <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"qinisekisa isihlungi esihlosiwe"</string>
+ <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Ivumela uhlelo lokusebenza ukuthi lihlole uma ngabe isihlungi esihlosiwe siqinisekisiwe noma asiqinisekisiwe."</string>
+ <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"hlanganisa kusiqinisekisi esihlosiwe sesihlungi"</string>
+ <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Ivumela umbambi ukuthi enze izicelo zeziqinisekisi ezihlosiwe zesihlungi. Akumele kudingelwe izinhlelo zokusebenza ezijwayelekile."</string>
<string name="permlab_serialPort" msgid="546083327654631076">"finyelela kuma- serial port"</string>
<string name="permdesc_serialPort" msgid="2991639985224598193">"Ivumela umnikai ukuthi athole inombolo ye-serial ukue angene kwiindawo ze-serial esebenzisa i-SerialManager API."</string>
<string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"finyelela abahlinzeki bokuqukethwe ngaphandle"</string>
@@ -1561,6 +1567,8 @@
<string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Yehlisa usuku"</string>
<string name="date_picker_increment_year_button" msgid="6318697384310808899">"Khulisa unyaka"</string>
<string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Yehlisa unyaka"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Inyanga edlule"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Inyanga ezayo"</string>
<string name="keyboardview_keycode_alt" msgid="4856868820040051939">"i-ALT"</string>
<string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Khansela"</string>
<string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Susa"</string>
@@ -1813,7 +1821,6 @@
<string name="select_minutes" msgid="3974345615920336087">"Khetha amaminithi"</string>
<string name="select_day" msgid="7774759604701773332">"Khetha inyanga nosuku"</string>
<string name="select_year" msgid="7952052866994196170">"Khetha unyaka"</string>
- <string name="item_is_selected" msgid="949687401682476608">"I-<xliff:g id="ITEM">%1$s</xliff:g> ekhethiwe"</string>
<string name="deleted_key" msgid="7659477886625566590">"I-<xliff:g id="KEY">%1$s</xliff:g> isusiwe"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Umsebenzi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="7570091317001980053">"Ukuze ususe ukuphina kulesi sikrini, thinta uphinde ubambe i-Emuva ne-Buka konke ngesikhathi esisodwa."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9895027..3945222 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4283,6 +4283,15 @@
<attr name="letterSpacing" />
<!-- Font feature settings. -->
<attr name="fontFeatureSettings" />
+ <!-- Break strategy (control over paragraph layout). -->
+ <attr name="breakStrategy">
+ <!-- Line breaking uses simple strategy. -->
+ <enum name="simple" value="0" />
+ <!-- Line breaking uses high-quality strategy, including hyphenation. -->
+ <enum name="high_quality" value="1" />
+ <!-- Line breaking stratgegy balances line lengths. -->
+ <enum name="balanced" value="2" />
+ </attr>
</declare-styleable>
<declare-styleable name="TextViewAppearance">
<!-- Base text color, typeface, size, and style. -->
@@ -4444,11 +4453,6 @@
</declare-styleable>
<declare-styleable name="DatePicker">
- <!-- The first year (inclusive), for example "1940". {@deprecated Use minDate instead.} -->
- <attr name="startYear" format="integer" />
- <!-- The last year (inclusive), for example "2010". {@deprecated Use maxDate instead.} -->
- <attr name="endYear" format="integer" />
-
<!-- The first day of week according to {@link java.util.Calendar}. -->
<attr name="firstDayOfWeek" />
<!-- The minimal date shown by this calendar view in mm/dd/yyyy format. -->
@@ -4474,12 +4478,14 @@
<!-- The background for the selected date header. -->
<attr name="headerBackground" />
- <!-- The list year's text appearance in the list. -->
+ <!-- The list year's text appearance in the list.
+ {@deprecated Use yearListTextColor. }-->
<attr name="yearListItemTextAppearance" format="reference" />
<!-- @hide The list year's text appearance in the list when activated. -->
<attr name="yearListItemActivatedTextAppearance" format="reference" />
<!-- The text color list of the calendar. -->
<attr name="calendarTextColor" format="color" />
+
<!-- Defines the look of the widget. Prior to the L release, the only choice was
spinner. As of L, with the Material theme selected, the default layout is calendar,
but this attribute can be used to force spinner to be used instead. -->
@@ -4490,17 +4496,29 @@
<enum name="calendar" value="2" />
</attr>
- <!-- @deprecated The text appearance for the month (ex. May) in the selected date header. -->
+ <!-- The first year (inclusive), for example "1940".
+ {@deprecated Use minDate instead.} -->
+ <attr name="startYear" format="integer" />
+ <!-- The last year (inclusive), for example "2010".
+ {@deprecated Use maxDate instead.} -->
+ <attr name="endYear" format="integer" />
+ <!-- The text appearance for the month (ex. May) in the selected date header.
+ {@deprecated Use headerTextColor instead.} -->
<attr name="headerMonthTextAppearance" format="reference" />
- <!-- @deprecated The text appearance for the day of month (ex. 28) in the selected date header. -->
+ <!-- The text appearance for the day of month (ex. 28) in the selected date header.
+ {@deprecated Use headerTextColor instead.} -->
<attr name="headerDayOfMonthTextAppearance" format="reference" />
- <!-- The text appearance for the year (ex. 2014) in the selected date header. -->
+ <!-- The text appearance for the year (ex. 2014) in the selected date header.
+ {@deprecated Use headerTextColor instead.} -->
<attr name="headerYearTextAppearance" format="reference" />
- <!-- @deprecated The background color for the header's day of week. -->
+ <!-- The background color for the header's day of week.
+ {@deprecated No longer displayed.} -->
<attr name="dayOfWeekBackground" format="color" />
- <!-- @deprecated The text color for the header's day of week. -->
+ <!-- The text color for the header's day of week.
+ {@deprecated No longer displayed.} -->
<attr name="dayOfWeekTextAppearance" format="reference" />
- <!-- @deprecated The list year's selected circle color in the list. -->
+ <!-- The list year's selected circle color in the list.
+ {@deprecated No longer displayed.} -->
<attr name="yearListSelectorColor" format="color" />
</declare-styleable>
@@ -7750,6 +7768,8 @@
<enum name="multi-select" value="4" />
<enum name="integer" value="5" />
<enum name="string" value="6" />
+ <enum name="bundle" value="7" />
+ <enum name="bundle_array" value="8" />
</attr>
<attr name="title" />
<attr name="description" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 283c237..b0b4e3a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1042,6 +1042,18 @@
libraries in the apk must be stored and page-aligned. -->
<attr name="extractNativeLibs" format="boolean"/>
+ <!-- Specify whether an activity intent filter will need to be verified thru its set
+ of data URIs. This will only be used when the Intent's action is set to
+ {@link android.content.Intent#ACTION_VIEW Intent.ACTION_VIEW} and the Intent's category is
+ set to {@link android.content.Intent#CATEGORY_BROWSABLE Intent.CATEGORY_BROWSABLE} and the
+ intern filter data scheme is set to "http" or "https". When set to true, the intent filter
+ will need to use its data tag for getting the URIs to verify with.
+
+ For each URI, an HTTPS network request will be done to <code>/.well-known/associations.json</code>
+ host to verify that the web site is okay with the app intercepting the URI.
+ -->
+ <attr name="autoVerify" format="boolean" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1840,6 +1852,7 @@
<attr name="banner" />
<attr name="logo" />
<attr name="priority" />
+ <attr name="autoVerify" />
</declare-styleable>
<!-- Attributes that can be supplied in an AndroidManifest.xml
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 3431f35..7d08e7f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -364,27 +364,26 @@
<dimen name="resolver_max_width">480dp</dimen>
- <!-- Size of the offset applied to the position of the circular mask. This is only
- used on circular displays. In the case where there is no "chin", this will default
- to 0 -->
- <dimen name="circular_display_mask_offset">0px</dimen>
+ <!-- Size of the offset applied to the position of the circular mask. This
+ is only used on circular displays. In the case where there is no
+ "chin", this will default to 0 -->
+ <dimen name="circular_display_mask_offset">0px</dimen>
+ <!-- Amount to reduce the size of the circular mask by (to compensate for
+ aliasing effects). This is only used on circular displays. -->
+ <dimen name="circular_display_mask_thickness">1px</dimen>
- <!-- Amount to reduce the size of the circular mask by (to compensate for aliasing
- effects). This is only used on circular displays. -->
- <dimen name="circular_display_mask_thickness">1px</dimen>
+ <dimen name="lock_pattern_dot_line_width">3dp</dimen>
+ <dimen name="lock_pattern_dot_size">12dp</dimen>
+ <dimen name="lock_pattern_dot_size_activated">28dp</dimen>
- <dimen name="lock_pattern_dot_line_width">3dp</dimen>
- <dimen name="lock_pattern_dot_size">12dp</dimen>
- <dimen name="lock_pattern_dot_size_activated">28dp</dimen>
+ <dimen name="text_handle_min_size">40dp</dimen>
- <dimen name="text_handle_min_size">40dp</dimen>
-
- <!-- Lighting and shadow properties -->
- <dimen name="light_y">-200dp</dimen>
- <dimen name="light_z">800dp</dimen>
- <dimen name="light_radius">600dp</dimen>
- <item type="dimen" format="float" name="ambient_shadow_alpha">0.075</item>
- <item type="dimen" format="float" name="spot_shadow_alpha">0.15</item>
+ <!-- Lighting and shadow properties -->
+ <dimen name="light_y">-200dp</dimen>
+ <dimen name="light_z">800dp</dimen>
+ <dimen name="light_radius">600dp</dimen>
+ <item type="dimen" format="float" name="ambient_shadow_alpha">0.075</item>
+ <item type="dimen" format="float" name="spot_shadow_alpha">0.15</item>
<!-- Floating toolbar dimensions -->
<dimen name="floating_toolbar_height">48dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ef7bfaf..f59a4d8 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2653,4 +2653,9 @@
<public type="attr" name="extractNativeLibs" />
<public type="attr" name="usesCleartextTraffic" />
+
+ <!--IntentFilter auto verification -->
+ <public type="attr" name="autoVerify" />
+ <public type="attr" name="breakStrategy" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ab0a55d..6cd3139 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1768,6 +1768,8 @@
<string name="permlab_cameraDisableTransmitLed">disable transmit indicator LED when camera is in use</string>
<!-- Description of a camera app permission, listed so the user can choose whether or not they want to allow it to disable the may-transmit light indicator. -->
<string name="permdesc_cameraDisableTransmitLed">Allows a pre-installed system application to disable the camera use indicator LED.</string>
+ <!-- Description of a camera app permission, listed so that the user can send the camera service notifications about system-wide events. -->
+ <string name="permdesc_cameraSendSystemEvent">Allows a pre-installed system application to send the camera service system events.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_brick" product="tablet">permanently disable tablet</string>
@@ -1897,6 +1899,10 @@
<string name="permdesc_performCdmaProvisioning">Allows the app to start CDMA provisioning.
Malicious apps may unnecessarily start CDMA provisioning.</string>
+ <string name="permlab_performSimActivation">start SIM card setup</string>
+ <string name="permdesc_performSimActivation">Allows the app to handle SIM activation requests.
+ The app may directly perform activation or may delegate to another app.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_locationUpdates">control location update notifications</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -3377,6 +3383,22 @@
<string name="permdesc_bindPackageVerifier">Allows the holder to make requests of
package verifiers. Should never be needed for normal apps.</string>
+ <!-- Title of an application permission which allows the application to verify whether
+ a different intent filter is able to be verified by some internal logic. [CHAR LIMIT=40] -->
+ <string name="permlab_intentFilterVerificationAgent">verify intent filter</string>
+ <!-- Description of an application permission which allows the application to verify whether
+ a different intent filter is able to be verified by some internal heuristic. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_intentFilterVerificationAgent">Allows the app to check if an intent filter
+ is verified or not.</string>
+
+ <!-- Title of an application permission which allows the application to verify whether
+ a different intent filter is able to be verified by some internal logic. [CHAR LIMIT=40] -->
+ <string name="permlab_bindIntentFilterVerifier">bind to an intent filter verifier</string>
+ <!-- Description of an application permission which allows the application to verify whether
+ a different intent filter is able to be verified by some internal logic. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_bindIntentFilterVerifier">Allows the holder to make requests of
+ intent filter verifiers. Should never be needed for normal apps.</string>
+
<!-- Title of an application permission which allows the application to access serial ports via the SerialManager. [CHAR LIMIT=40] -->
<string name="permlab_serialPort">access serial ports</string>
<!-- Description of an application permission which allows the application access serial ports via the SerialManager. [CHAR LIMIT=NONE] -->
@@ -4425,6 +4447,10 @@
<string name="date_picker_increment_year_button">Increase year</string>
<!-- Description of the button to decrease the DatePicker's year value. [CHAR LIMIT=NONE] -->
<string name="date_picker_decrement_year_button">Decrease year</string>
+ <!-- Description of the button to move to the previous month. [CHAR LIMIT=NONE] -->
+ <string name="date_picker_prev_month_button">Previous month</string>
+ <!-- Description of the button to move to the next month. [CHAR LIMIT=NONE] -->
+ <string name="date_picker_next_month_button">Next month</string>
<!-- KeyboardView - accessibility support -->
<!-- Description of the Alt button in a KeyboardView. [CHAR LIMIT=NONE] -->
@@ -5088,8 +5114,6 @@
<string name="select_day">Select month and day</string>
<!-- Accessibility announcement for the year picker [CHAR LIMIT=NONE] -->
<string name="select_year">Select year</string>
- <!-- Accessibility description for the item that is currently selected. -->
- <string name="item_is_selected"><xliff:g id="item" example="2013">%1$s</xliff:g> selected</string>
<!-- Accessibility announcement when a number that had been typed in is deleted [CHAR_LIMIT=NONE] -->
<string name="deleted_key"><xliff:g id="key" example="4">%1$s</xliff:g> deleted</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index cc64b43..3c3d286 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -497,6 +497,7 @@
<item name="textEditSideNoPasteWindowLayout">?attr/textEditSideNoPasteWindowLayout</item>
<item name="textEditSuggestionItemLayout">?attr/textEditSuggestionItemLayout</item>
<item name="textCursorDrawable">?attr/textCursorDrawable</item>
+ <item name="breakStrategy">high_quality</item>
</style>
<style name="Widget.CheckedTextView">
@@ -527,6 +528,7 @@
<item name="textAppearance">?attr/textAppearanceMediumInverse</item>
<item name="textColor">?attr/editTextColor</item>
<item name="gravity">center_vertical</item>
+ <item name="breakStrategy">simple</item>
</style>
<style name="Widget.ExpandableListView" parent="Widget.ListView">
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 223578d..23ac221 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -240,10 +240,6 @@
<!-- @deprecated Action bars are now themed using the inheritable android:theme attribute. -->
<style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse"/>
<style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Material.Widget.ActionBar.Menu"/>
- <style name="TextAppearance.DeviceDefault.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material.DatePicker.DayOfWeekLabel"/>
- <style name="TextAppearance.DeviceDefault.DatePicker.MonthLabel" parent="TextAppearance.Material.DatePicker.MonthLabel"/>
- <style name="TextAppearance.DeviceDefault.DatePicker.DayOfMonthLabel" parent="TextAppearance.Material.DatePicker.DayOfMonthLabel"/>
- <style name="TextAppearance.DeviceDefault.DatePicker.YearLabel" parent="TextAppearance.Material.DatePicker.YearLabel"/>
<!-- Preference Styles -->
<style name="Preference.DeviceDefault" parent="Preference.Material"/>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 472908c..9cf7884 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -389,32 +389,14 @@
<item name="textColor">@color/primary_text_secondary_when_activated_material_inverse</item>
</style>
- <style name="TextAppearance.Material.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material">
- <item name="includeFontPadding">false</item>
- <item name="textColor">?attr/textColorPrimaryInverse</item>
- <item name="textSize">@dimen/datepicker_header_text_size</item>
- </style>
-
- <style name="TextAppearance.Material.DatePicker.MonthLabel" parent="TextAppearance.Material">
- <item name="includeFontPadding">false</item>
- <item name="textColor">@color/date_picker_header_text_material</item>
- <item name="textSize">@dimen/datepicker_selected_date_month_size</item>
- </style>
-
- <style name="TextAppearance.Material.DatePicker.DayOfMonthLabel" parent="TextAppearance.Material">
- <item name="includeFontPadding">false</item>
- <item name="textColor">@color/date_picker_header_text_material</item>
- <item name="textSize">@dimen/datepicker_selected_date_day_size</item>
- </style>
-
<style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material">
- <item name="textColor">@color/date_picker_header_text_material</item>
+ <item name="textColor">@color/primary_text_secondary_when_activated_material_inverse</item>
<item name="textSize">@dimen/date_picker_year_label_size</item>
<item name="fontFamily">sans-serif-medium</item>
</style>
<style name="TextAppearance.Material.DatePicker.DateLabel" parent="TextAppearance.Material">
- <item name="textColor">@color/date_picker_header_text_material</item>
+ <item name="textColor">@color/primary_text_secondary_when_activated_material_inverse</item>
<item name="textSize">@dimen/date_picker_date_label_size</item>
<item name="fontFamily">sans-serif-medium</item>
</style>
@@ -675,8 +657,7 @@
<item name="calendarViewShown">true</item>
<!-- Attributes for new-style DatePicker. -->
<item name="internalLayout">@layout/date_picker_material</item>
- <item name="yearListItemTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item>
- <item name="yearListItemActivatedTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel.Activated</item>
+ <item name="headerTextColor">@color/primary_text_secondary_when_activated_material</item>
<item name="headerBackground">#ff555555</item>
</style>
@@ -1038,6 +1019,7 @@
</style>
<style name="Widget.Material.Light.DatePicker" parent="Widget.Material.DatePicker">
+ <item name="headerTextColor">@color/primary_text_secondary_when_activated_material_inverse</item>
<item name="headerBackground">?attr/colorAccent</item>
</style>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 32a2ec1..220d5e7 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2049,7 +2049,6 @@
<java-symbol type="integer" name="config_downtime_condition_lookahead_threshold_hrs" />
<java-symbol type="string" name="muted_by" />
- <java-symbol type="string" name="item_is_selected" />
<java-symbol type="string" name="select_day" />
<java-symbol type="string" name="select_year" />
@@ -2199,9 +2198,15 @@
<java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.Month" />
<java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.DayOfWeek" />
<java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.Day" />
+ <java-symbol type="style" name="TextAppearance.Material.DatePicker.List.YearLabel" />
+ <java-symbol type="style" name="TextAppearance.Material.DatePicker.List.YearLabel.Activated" />
<java-symbol type="dimen" name="day_picker_padding_top"/>
<java-symbol type="dimen" name="date_picker_day_of_week_height"/>
+ <java-symbol type="string" name="storage_internal" />
+ <java-symbol type="string" name="storage_sd_card" />
+ <java-symbol type="string" name="storage_usb" />
+
<java-symbol type="id" name="accessibility_action_show_on_screen" />
<!-- Floating toolbar -->
@@ -2214,4 +2219,11 @@
<java-symbol type="dimen" name="floating_toolbar_menu_button_minimum_width" />
<java-symbol type="dimen" name="floating_toolbar_default_width" />
<java-symbol type="dimen" name="floating_toolbar_minimum_overflow_height" />
+
+ <java-symbol type="drawable" name="ic_chevron_left" />
+ <java-symbol type="drawable" name="ic_chevron_right" />
+ <java-symbol type="string" name="date_picker_prev_month_button" />
+ <java-symbol type="string" name="date_picker_next_month_button" />
+ <java-symbol type="layout" name="date_picker_month_item_material" />
+ <java-symbol type="id" name="month_view" />
</resources>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index bfaea8f..b07d338 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -113,6 +113,9 @@
<application android:theme="@style/Theme">
<uses-library android:name="android.test.runner" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
+ <meta-data
+ android:name="android.content.APP_RESTRICTIONS"
+ android:resource="@xml/app_restrictions" />
<activity android:name="android.view.ViewAttachTestActivity" android:label="View Attach Test">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index ce0d9a2..04b0478 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -135,4 +135,8 @@
<string name="first">Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.</string>
<string name="actor">Abe Lincoln</string>
<string name="caption">Lincoln adressing the crowd at Gettysburgh</string>
+
+ <!-- RestrictionsManagerTest -->
+ <string name="restrictionManager_title">Title</string>
+ <string name="restrictionManager_desc">Description</string>
</resources>
diff --git a/core/tests/coretests/res/xml/app_restrictions.xml b/core/tests/coretests/res/xml/app_restrictions.xml
new file mode 100644
index 0000000..c84cabcc
--- /dev/null
+++ b/core/tests/coretests/res/xml/app_restrictions.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
+ <restriction android:key="hidden_key"
+ android:restrictionType="hidden"/>
+ <restriction
+ android:defaultValue="true"
+ android:description="@string/restrictionManager_desc"
+ android:key="bool_key"
+ android:restrictionType="bool"
+ android:title="@string/restrictionManager_title"/>
+ <restriction
+ android:defaultValue="test"
+ android:key="string_key"
+ android:restrictionType="string"/>
+
+ <restriction android:key="int_key"
+ android:restrictionType="integer"
+ android:defaultValue="15"/>
+ <restriction android:key="bundle_key"
+ android:restrictionType="bundle">
+ <restriction
+ android:key="bundle_string_key"
+ android:restrictionType="string"/>
+ <restriction
+ android:defaultValue="true"
+ android:key="bundle_bool_key"
+ android:restrictionType="bool"/>
+
+ </restriction>
+ <restriction android:key="bundle_array_key"
+ android:restrictionType="bundle_array">
+ <restriction android:key="bundle_array_int"
+ android:restrictionType="integer"/>
+ <restriction android:key="bundle_array_bundle_key"
+ android:restrictionType="bundle">
+ <restriction android:key="bundle_array_bundle_int_key"
+ android:restrictionType="integer"/>
+ </restriction>
+ </restriction>
+</restrictions>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/RestrictionsManagerTest.java b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
new file mode 100644
index 0000000..8921924
--- /dev/null
+++ b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.content;
+
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.test.AndroidTestCase;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class RestrictionsManagerTest extends AndroidTestCase {
+ private RestrictionsManager mRm;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mRm = (RestrictionsManager) mContext.getSystemService(Context.RESTRICTIONS_SERVICE);
+ }
+
+ public void testGetManifestRestrictions() {
+ String packageName = getContext().getPackageName();
+ List<RestrictionEntry> manifestRestrictions = mRm.getManifestRestrictions(packageName);
+ assertEquals(6, manifestRestrictions.size());
+ Set<String> verifiedKeys = new HashSet<>(Arrays.asList("bundle_key", "bundle_array_key",
+ "bundle_array_bundle_key"));
+ for (RestrictionEntry entry : manifestRestrictions) {
+ if ("bundle_key".equals(entry.getKey())) {
+ assertEquals("bundle_key entry should have 2 children entries",
+ 2, entry.getRestrictions().length);
+ verifiedKeys.remove(entry.getKey());
+ } else if ("bundle_array_key".equals(entry.getKey())) {
+ assertEquals("bundle_array_key should have 2 children entries",
+ 2, entry.getRestrictions().length);
+ assertNotNull(entry.getRestrictions());
+ for (RestrictionEntry childEntry : entry.getRestrictions()) {
+ if ("bundle_array_bundle_key".equals(childEntry.getKey())) {
+ assertNotNull(childEntry.getRestrictions());
+ assertEquals("bundle_array_bundle_key should have 1 child entry",
+ 1, childEntry.getRestrictions().length);
+ verifiedKeys.remove(childEntry.getKey());
+ }
+ }
+ verifiedKeys.remove(entry.getKey());
+ }
+ }
+ assertTrue("Entries" + verifiedKeys + " were not found", verifiedKeys.isEmpty());
+ }
+
+ public void testConvertRestrictionsToBundle() {
+ String packageName = getContext().getPackageName();
+ List<RestrictionEntry> manifestRestrictions = mRm.getManifestRestrictions(packageName);
+ Bundle bundle = RestrictionsManager.convertRestrictionsToBundle(manifestRestrictions);
+ assertEquals(6, bundle.size());
+ Bundle childBundle = bundle.getBundle("bundle_key");
+ assertNotNull(childBundle);
+ assertEquals(2, childBundle.size());
+ Parcelable[] childBundleArray = bundle.getParcelableArray("bundle_array_key");
+ assertEquals(2, childBundleArray.length);
+ }
+
+}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index cd45017..6fa28b1 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -804,4 +804,56 @@
assertFalse(Uri.parse("content://com.example/path/path").isPathPrefixMatch(
Uri.parse("content://com.example/path%2Fpath")));
}
+
+ public void testToSafeString() {
+ checkToSafeString("tel:xxxxxx", "tel:Google");
+ checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
+ checkToSafeString("tEl:xxx.xxx-xxxx", "tEl:123.456-7890");
+
+ checkToSafeString("sms:xxxxxx", "sms:123abc");
+ checkToSafeString("smS:xxx.xxx-xxxx", "smS:123.456-7890");
+
+ checkToSafeString("smsto:xxxxxx", "smsto:123abc");
+ checkToSafeString("SMSTo:xxx.xxx-xxxx", "SMSTo:123.456-7890");
+
+ checkToSafeString("mailto:xxxxxxx@xxxxxxx.xxx", "mailto:android@android.com");
+ checkToSafeString("Mailto:xxxxxxx@xxxxxxx.xxxxxxxxxx",
+ "Mailto:android@android.com/secret");
+
+ checkToSafeString("sip:xxxxxxx@xxxxxxx.xxxxxxxx", "sip:android@android.com:1234");
+ checkToSafeString("sIp:xxxxxxx@xxxxxxx.xxx", "sIp:android@android.com");
+
+ checkToSafeString("http://www.android.com/...", "http://www.android.com");
+ checkToSafeString("HTTP://www.android.com/...", "HTTP://www.android.com");
+ checkToSafeString("http://www.android.com/...", "http://www.android.com/");
+ checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
+ checkToSafeString("http://www.android.com/...",
+ "http://user:pwd@www.android.com/secretUrl?param");
+ checkToSafeString("http://www.android.com/...",
+ "http://user@www.android.com/secretUrl?param");
+ checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
+ checkToSafeString("http:///...", "http:///path?param");
+ checkToSafeString("http:///...", "http://");
+ checkToSafeString("http://:12345/...", "http://:12345/");
+
+ checkToSafeString("https://www.android.com/...", "https://www.android.com/secretUrl?param");
+ checkToSafeString("https://www.android.com:8443/...",
+ "https://user:pwd@www.android.com:8443/secretUrl?param");
+ checkToSafeString("https://www.android.com/...", "https://user:pwd@www.android.com");
+ checkToSafeString("Https://www.android.com/...", "Https://user:pwd@www.android.com");
+
+ checkToSafeString("ftp://ftp.android.com/...", "ftp://ftp.android.com/");
+ checkToSafeString("ftP://ftp.android.com/...", "ftP://anonymous@ftp.android.com/");
+ checkToSafeString("ftp://ftp.android.com:2121/...",
+ "ftp://root:love@ftp.android.com:2121/");
+
+ checkToSafeString("unsupported://ajkakjah/askdha/secret?secret",
+ "unsupported://ajkakjah/askdha/secret?secret");
+ checkToSafeString("unsupported:ajkakjah/askdha/secret?secret",
+ "unsupported:ajkakjah/askdha/secret?secret");
+ }
+
+ private void checkToSafeString(String expectedSafeString, String original) {
+ assertEquals(expectedSafeString, Uri.parse(original).toSafeString());
+ }
}
diff --git a/docs/html/google/gcm/c2dm.jd b/docs/html/google/gcm/c2dm.jd
index 6ae7c1a..d0f8c71 100644
--- a/docs/html/google/gcm/c2dm.jd
+++ b/docs/html/google/gcm/c2dm.jd
@@ -33,7 +33,10 @@
</div>
</div>
-<p>Android Cloud to Device Messaging (C2DM) is deprecated. The C2DM service will continue to be maintained in the short term, but C2DM will accept no new users, and it will grant no new quotas. <strong>C2DM developers are strongly encouraged to move to Google Cloud Messaging (GCM)</strong>. GCM is the next generation of C2DM.</p>
+<p>Android Cloud to Device Messaging (C2DM) was officially deprecated on June 26, 2012, and has been
+ shut down completely as of April 1, 2015. <strong>C2DM developers are strongly encouraged to move
+ to Google Cloud Messaging (GCM)</strong>. GCM is the next generation of C2DM.</p>
+
<p>This document is addressed to C2DM developers who are moving to GCM. It describes the differences between GCM and C2DM, and explains how to migrate existing C2DM apps to GCM.</p>
diff --git a/docs/html/guide/index.jd b/docs/html/guide/index.jd
index d78a1b1..cb4f65c 100644
--- a/docs/html/guide/index.jd
+++ b/docs/html/guide/index.jd
@@ -30,7 +30,7 @@
work in the background.</p>
<p>From one component you can start another component using an <em>intent</em>. You can even start
-a component in a different app, such an activity in a maps app to show an address. This model
+a component in a different app, such as an activity in a maps app to show an address. This model
provides multiple entry points for a single app and allows any app to behave as a user's "default"
for an action that other apps may invoke.</p>
diff --git a/docs/html/images/tv/channel-info.png b/docs/html/images/tv/channel-info.png
new file mode 100644
index 0000000..5a48078
--- /dev/null
+++ b/docs/html/images/tv/channel-info.png
Binary files differ
diff --git a/docs/html/images/tv/do-not-attempt.png b/docs/html/images/tv/do-not-attempt.png
new file mode 100644
index 0000000..18a8775
--- /dev/null
+++ b/docs/html/images/tv/do-not-attempt.png
Binary files differ
diff --git a/docs/html/images/tv/prog-guide.png b/docs/html/images/tv/prog-guide.png
new file mode 100644
index 0000000..caa2278
--- /dev/null
+++ b/docs/html/images/tv/prog-guide.png
Binary files differ
diff --git a/docs/html/images/tv/tvinput-life.png b/docs/html/images/tv/tvinput-life.png
new file mode 100644
index 0000000..fc53f89
--- /dev/null
+++ b/docs/html/images/tv/tvinput-life.png
Binary files differ
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index b08fbcf..e8706c1 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -78,6 +78,19 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>Build Tools, Revision 22.0.1</a> <em>(March 2015)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+ <p>Fixed compatibility issues with
+ <a href="{@docRoot}guide/topics/renderscript/compute.html">RenderScript</a> kernels on
+ Android 4.4 (API level 19) to Android 4.1 (API level 16) devices.</p>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>Build Tools, Revision 22.0.0</a> <em>(March 2015)</em>
</p>
<div class="toggle-content-toggleme">
diff --git a/docs/html/training/custom-views/optimizing-view.jd b/docs/html/training/custom-views/optimizing-view.jd
index 7f2e762..022618b 100644
--- a/docs/html/training/custom-views/optimizing-view.jd
+++ b/docs/html/training/custom-views/optimizing-view.jd
@@ -12,33 +12,21 @@
<div id="tb">
<h2>This lesson teaches you to</h2>
- <ol>
- <li><a href="#less">Do Less, Less Frequently</a></li>
- <li><a href="#accelerate">Use Hardware Acceleration</a></li>
- </ol>
-
- <h2>You should also read</h2>
<ul>
- <li><a href="{@docRoot}guide/topics/graphics/hardware-accel.html">
- Hardware Acceleration
- </a>
- </li>
- </ul>
-<h2>Try it out</h2>
-<div class="download-box">
-<a href="{@docRoot}shareables/training/CustomView.zip"
-class="button">Download the sample</a>
-<p class="filename">CustomView.zip</p>
-</div>
-</div>
+ <li><a href="#less">Do Less, Less Frequently</a></li>
+ </ul>
+ <h2>Try it out</h2>
+ <div class="download-box">
+ <a href="{@docRoot}shareables/training/CustomView.zip"
+ class="button">Download the sample</a>
+ <p class="filename">CustomView.zip</p>
</div>
-
+ </div>
+</div>
<p>Now that you have a well-designed view that responds to gestures and transitions between states,
-you need to ensure
-that the view runs fast. To avoid a UI that feels sluggish or stutters during playback, you must
-ensure that your
-animations consistently run at 60 frames per second.</p>
+ensure that the view runs fast. To avoid a UI that feels sluggish or stutters during playback,
+ensure that animations consistently run at 60 frames per second.</p>
<h2 id="less">Do Less, Less Frequently</h2>
@@ -52,19 +40,13 @@
allocation while an
animation is running.</p>
-<p>In addition to making {@link android.view.View#onDraw onDraw()} leaner, you should also make sure
+<p>In addition to making {@link android.view.View#onDraw onDraw()} leaner, also make sure
it's called as
infrequently as possible. Most calls to {@link android.view.View#onDraw onDraw()} are the result of
a call to {@link
android.view.View#invalidate() invalidate()}, so eliminate unnecessary calls to {@link
android.view.View#invalidate()
-invalidate()}. When possible, call the four-parameter variant of {@link
-android.view.View#invalidate() invalidate()}
-rather than the version that takes no parameters. The no-parameter variant invalidates the entire
-view, while the
-four-parameter variant invalidates only a specified portion of the view. This approach allows draw calls to
-be more efficient and
-can eliminate unnecessary invalidation of views that fall outside the invalid rectangle.</p>
+invalidate()}.</p>
<p>Another very expensive operation is traversing layouts. Any time a view calls {@link
android.view.View#requestLayout()
@@ -78,7 +60,7 @@
as shallow as
possible.</p>
-<p>If you have a complex UI, you should consider writing a custom {@link android.view.ViewGroup
+<p>If you have a complex UI, consider writing a custom {@link android.view.ViewGroup
ViewGroup} to perform
its layout. Unlike the built-in views, your custom view can make application-specific assumptions
about the size and
@@ -88,89 +70,3 @@
views, but it never
measures them. Instead, it sets their sizes directly according to its own custom layout
algorithm.</p>
-
-<h2 id="accelerate">Use Hardware Acceleration</h2>
-
-<p>As of Android 3.0, the Android 2D graphics system can be accelerated by the GPU (Graphics
-Processing Unit) hardware
-found in most newer Android devices. GPU hardware acceleration can result in a tremendous
-performance increase for many
-applications, but it isn't the right choice for every application. The Android framework
-gives you the ability to finely control which parts of your application are or are not
-hardware accelerated.</p>
-
-<p>See <a href="{@docRoot}guide/topics/graphics/hardware-accel.html">Hardware Acceleration</a>
- in the Android Developers Guide for directions on how to enable acceleration at the
- application, activity, or window level. Notice that in addition to the directions in
- the developer guide, you must also set your application's target API to 11 or higher by
- specifying {@code <uses-sdk
- android:targetSdkVersion="11"/>} in your {@code AndroidManifest.xml} file.</p>
-
-<p>Once you've enabled hardware acceleration, you may or may not see a performance increase.
-Mobile GPUs are very good at certain tasks, such as scaling, rotating, and translating
-bitmapped images. They are not particularly good at other tasks, such as drawing lines or curves. To
-get the most out of GPU acceleration, you should maximize the number of operations that the GPU is
-good at, and minimize the number of operations that the GPU isn't good at.</p>
-
-<p>In the PieChart example, for instance, drawing the pie is relatively expensive. Redrawing the pie
-each time it's
-rotated causes the UI to feel sluggish. The solution is to place the pie chart into a child
-{@link android.view.View} and set that
-{@link android.view.View}'s
-<a href="{@docRoot}reference/android/view/View.html#setLayerType(int, android.graphics.Paint)">
- layer type</a> to {@link android.view.View#LAYER_TYPE_HARDWARE}, so that the GPU can cache it as
-a static
-image. The sample
-defines the child view as an inner class of {@code PieChart}, which minimizes the amount of code
-changes that are needed
-to implement this solution.</p>
-
-<pre>
- private class PieView extends View {
-
- public PieView(Context context) {
- super(context);
- if (!isInEditMode()) {
- setLayerType(View.LAYER_TYPE_HARDWARE, null);
- }
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- for (Item it : mData) {
- mPiePaint.setShader(it.mShader);
- canvas.drawArc(mBounds,
- 360 - it.mEndAngle,
- it.mEndAngle - it.mStartAngle,
- true, mPiePaint);
- }
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- mBounds = new RectF(0, 0, w, h);
- }
-
- RectF mBounds;
- }
-</pre>
-
-<p>After this code change, {@code PieChart.PieView.onDraw()} is called only when the view is first
-shown. During the rest
-of the application's lifetime, the pie chart is cached as an image, and redrawn at different
-rotation angles by the GPU.
-GPU hardware is particularly good at this sort of thing, and the performance difference is
-immediately noticeable.</p>
-
-<p>There is a tradeoff, though. Caching images as hardware layers consumes video memory, which is a
-limited resource.
-For this reason, the final version of {@code PieChart.PieView} only sets its layer type to
-{@link android.view.View#LAYER_TYPE_HARDWARE}
-while the user is actively scrolling. At all other times, it sets its layer type to
-{@link android.view.View#LAYER_TYPE_NONE}, which
-allows the GPU to stop caching the image.</p>
-
-<p>Finally, don't forget to profile your code. Techniques that improve performance on one view
-might negatively affect performance on another.</p>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 11ae1a6..2873b5b 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -998,10 +998,25 @@
Building TV Games</a>
</li>
- <li>
- <a href="<?cs var:toroot ?>training/tv/tif/index.html"
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/tv/tif/index.html"
description="How to build Live TV apps.">
Building Live TV Apps</a>
+ </div>
+ <ul>
+ <li>
+ <a href="<?cs var:toroot ?>training/tv/tif/tvinput.html">
+ Developing a TV Input Service</a>
+ <li>
+ <a href="<?cs var:toroot ?>training/tv/tif/channel.html">
+ Working with Channel Data</a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/tv/tif/ui.html">
+ Managing User Interaction</a>
+ </li>
+ </ul>
</li>
<li>
diff --git a/docs/html/training/tv/tif/channel.jd b/docs/html/training/tv/tif/channel.jd
new file mode 100644
index 0000000..999f1ca
--- /dev/null
+++ b/docs/html/training/tv/tif/channel.jd
@@ -0,0 +1,239 @@
+page.title=Working with Channel Data
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#permission">Get Permission</a></li>
+ <li><a href="#register">Register Channels in the Database</a></li>
+ <li><a href="#update">Update Channel Data</a></li>
+ </ol>
+ <h2>Try It Out</h2>
+ <ul>
+ <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+ TV Input Service sample app</a></li>
+ </ul>
+</div>
+</div>
+
+<p>Your TV input must provide Electronic Program Guide (EPG) data for at least one channel in its
+setup activity. You should also periodically update that data, with consideration for the size of
+the update and the processing thread that handles it. This lesson discusses creating and updating
+channel and program data on the system database with these considerations in mind.</p>
+
+<p> </p>
+
+<h2 id="permission">Get Permission</h2>
+
+<p>In order for your TV input to work with EPG data, it must declare the
+read and write permissions in its Android manifest file as follows:</p>
+
+<pre>
+<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
+<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
+</pre>
+
+<h2 id="register">Register Channels in the Database</h2>
+
+<p>The Android TV system database maintains records of channel data for TV inputs. In your setup
+activity, for each of your channels, you must map your channel data to the following fields of the
+{@link android.media.tv.TvContract.Channels} class:</p>
+
+<ul>
+ <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NAME} - the displayed name of the
+ channel</li>
+ <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER} - the displayed channel
+ number</li>
+ <li>{@link android.media.tv.TvContract.Channels#COLUMN_INPUT_ID} - the ID of the TV input service</li>
+ <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_TYPE} - the channel's service type</li>
+ <li>{@link android.media.tv.TvContract.Channels#COLUMN_TYPE} - the channel's broadcast standard
+ type</li>
+ <li>{@link android.media.tv.TvContract.Channels#COLUMN_VIDEO_FORMAT} - the default video format
+ for the channel</li>
+</ul>
+
+<p>Although the TV input framework is generic enough to handle both traditional broadcast and
+over-the-top (OTT) content without any distinction, you may want to define the following columns in
+addition to those above to better identify traditional broadcast channels:</p>
+
+<ul>
+ <li>{@link android.media.tv.TvContract.Channels#COLUMN_ORIGINAL_NETWORK_ID} - the television
+ network ID</li>
+ <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_ID} - the service ID</li>
+ <li>{@link android.media.tv.TvContract.Channels#COLUMN_TRANSPORT_STREAM_ID} - the transport stream
+ ID</li>
+</ul>
+
+<p>For internet streaming based TV inputs, assign your own values to the above accordingly so that
+each channel can be identified uniquely.</p>
+
+<p>Pull your channel metadata (in XML, JSON, or whatever) from your backend server, and in your setup
+activity map the values to the system database as follows:</p>
+
+<pre>
+ContentValues values = new ContentValues();
+
+values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.mNumber);
+values.put(Channels.COLUMN_DISPLAY_NAME, channel.mName);
+values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.mOriginalNetworkId);
+values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.mTransportStreamId);
+values.put(Channels.COLUMN_SERVICE_ID, channel.mServiceId);
+values.put(Channels.COLUMN_VIDEO_FORMAT, channel.mVideoFormat);
+
+Uri uri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
+</pre>
+
+<p>In the example above, <code>channel</code> is an object which holds channel metadata from the
+backend server.</p>
+
+<h3 id="art">Present Channel and Program Information</h2>
+
+<p>The system TV app presents channel and program information to users as they flip through channels,
+as shown in figure 1. To make sure the channel and program information works with the system TV app's
+channel and program information presenter, follow the guidelines below.</p>
+
+<ol>
+<li><strong>Channel number</strong> ({@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER})
+<li><strong>Icon</strong>
+(<a href="guide/topics/manifest/application-element.html#icon"><code>android:icon</code></a> in the
+TV input's manifest)</li>
+<li><strong>Program description</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_SHORT_DESCRIPTION})
+<li><strong>Program title</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_TITLE})</li>
+<li><strong>Channel logo</strong> ({@link android.media.tv.TvContract.Channels.Logo})
+ <ul>
+ <li>Use the color #EEEEEE to match the surrounding text</li>
+ <li>Don't include padding
+ </ul></li>
+<li><strong>Poster art</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_POSTER_ART_URI})
+ <ul>
+ <li>Aspect ratio between 16:9 and 4:3</li>
+ </ul>
+</ol>
+
+<img src="{@docRoot}images/tv/channel-info.png" id="figure1">
+<p class="img-caption">
+ <strong>Figure 1.</strong> The system TV app channel and program information presenter.
+</p>
+
+<p>The system TV app provides the same information through the program guide, including poster art,
+as shown in figure 2.</p>
+
+<img src="{@docRoot}images/tv/prog-guide.png" id="figure2">
+<p class="img-caption">
+ <strong>Figure 2.</strong> The system TV app program guide.
+</p>
+
+<h2 id="update">Update Channel Data</h2>
+
+<p>When updating existing channel data, use the
+{@link android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues,
+java.lang.String, java.lang.String[]) update()}
+method instead of deleting and re-adding the data. You can identify the current version of the data
+by using {@link android.media.tv.TvContract.Channels#COLUMN_VERSION_NUMBER Channels.COLUMN_VERSION_NUMBER}
+and {@link android.media.tv.TvContract.Programs#COLUMN_VERSION_NUMBER Programs.COLUMN_VERSION_NUMBER}
+when choosing the records to update.</p>
+
+<p class="note"><strong>Note:</strong> Adding channel data to the {@link android.content.ContentProvider}
+can take time. Only add current programs (those within two hours of the current time) when you update,
+and use a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">Sync Adapter</a> to
+update the rest of the channel data in the background. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
+Android TV Live TV Sample App</a> for an example.</p>
+
+<h3 id="batch">Batch Loading Channel Data</h3>
+
+<p>When updating the system database with a large amount of channel data, use the {@link android.content.ContentResolver}
+{@link android.content.ContentResolver#applyBatch applyBatch()}
+or
+{@link android.content.ContentResolver#bulkInsert(android.net.Uri, android.content.ContentValues[]) bulkInsert()}
+method. Here's an example using {@link android.content.ContentResolver#applyBatch applyBatch()}:<p>
+
+<pre>
+ArrayList<ContentProviderOperation> ops = new ArrayList<>();
+int programsCount = mChannelInfo.mPrograms.size();
+for (int j = 0; j < programsCount; ++j) {
+ ProgramInfo program = mChannelInfo.mPrograms.get(j);
+ ops.add(ContentProviderOperation.newInsert(
+ TvContract.Programs.CONTENT_URI)
+ .withValues(programs.get(j))
+ .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS,
+ programStartSec * 1000)
+ .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS,
+ (programStartSec + program.mDurationSec) * 1000)
+ .build());
+ programStartSec = programStartSec + program.mDurationSec;
+ if (j % 100 == 99 || j == programsCount - 1) {
+ try {
+ <strong>getContentResolver().applyBatch(TvContract.AUTHORITY, ops);</strong>
+ } catch (RemoteException | OperationApplicationException e) {
+ Log.e(TAG, "Failed to insert programs.", e);
+ return;
+ }
+ ops.clear();
+ }
+}
+</pre>
+
+<h3 id="async">Processing Channel Data Asynchronously</h3>
+
+<p>Data manipulation, such as fetching a stream from the server or accessing the database, should
+not block the UI thread. Using an {@link android.os.AsyncTask} is one
+way to perform updates asynchronously. For example, when loading channel info from a backend server,
+you can use {@link android.os.AsyncTask} as follows:</p>
+
+<pre>
+private static class LoadTvInputTask extends AsyncTask<Uri, Void, Void>> {
+
+ private Context mContext;
+
+ public LoadTvInputTask(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ protected Void doInBackground(Uri... uris) {
+ try {
+ fetchUri(uris[0]);
+ } catch (IOException e) {
+ Log.d(“LoadTvInputTask”, “fetchUri error”);
+ }
+ return null;
+ }
+
+ private void fetchUri(Uri videoUri) throws IOException {
+ InputStream inputStream = null;
+ try {
+ inputStream = mContext.getContentResolver().openInputStream(videoUri);
+ XmlPullParser parser = Xml.newPullParser();
+ try {
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+ parser.setInput(inputStream, null);
+ sTvInput = ChannelXMLParser.parseTvInput(parser);
+ sSampleChannels = ChannelXMLParser.parseChannelXML(parser);
+ } catch (XmlPullParserException e) {
+ e.printStackTrace();
+ }
+ } finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ }
+}
+</pre>
+
+<p>If you need to update EPG data on a regular basis, consider using
+a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">
+Sync Adapter</a> or {@link android.app.job.JobScheduler} to run the update process during idle time,
+such as every day at 3:00 a.m. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
+Android TV live TV sample app</a> for an example.</p>
+
+<p>Other techniques to separate the data update tasks from the UI thread include using the
+{@link android.os.HandlerThread} class, or you may implement your own using {@link android.os.Looper}
+and {@link android.os.Handler} classes. See <a href="{@docRoot}guide/components/processes-and-threads.html">
+Processes and Threads</a> for more information.</p>
\ No newline at end of file
diff --git a/docs/html/training/tv/tif/index.jd b/docs/html/training/tv/tif/index.jd
index 9c10850..5739294 100644
--- a/docs/html/training/tv/tif/index.jd
+++ b/docs/html/training/tv/tif/index.jd
@@ -1,17 +1,26 @@
page.title=Building Live TV Apps
page.tags=tv, tif
helpoutsWidget=true
-page.article=true
+startpage=true
@jd:body
<div id="tb-wrapper">
<div id="tb">
+ <h2>Dependencies and Prerequisites</h2>
+ <ul>
+ <li>Android 5.0 (API level 21) or higher</li>
+ </ul>
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}reference/android/media/tv/package-summary.html">
android.media.tv</a></li>
</ul>
+ <h2>Try It Out</h2>
+ <ul>
+ <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+ TV Input Service sample app</a></li>
+ </ul>
</div>
</div>
@@ -44,6 +53,17 @@
Building a TV input service for your content can help make it more accessible on TV devices.
</p>
-<p>For more information about TV Input Framework, see the
-<a href="{@docRoot}reference/android/media/tv/package-summary.html">android.media.tv</a>
-reference.</p>
+<h2>Topics</h2>
+
+<dl>
+ <dt><b><a href="tvinput.html">Developing a TV Input Service</a></b></dt>
+ <dd>Learn how to develop a TV input service, which works with the system TV app.</dd>
+
+ <dt><b><a href="channel.html">Working with Channel Data</a></b></dt>
+ <dd>Learn how to describe channel and program data for the system.</dd>
+
+ <dt><b><a href="ui.html">Managing User Interaction</a></b></dt>
+ <dd>Learn how to present overlays, manage content availability, and handle content selection.</dd>
+</dl>
+
+
diff --git a/docs/html/training/tv/tif/tvinput.jd b/docs/html/training/tv/tif/tvinput.jd
new file mode 100644
index 0000000..91f8ded
--- /dev/null
+++ b/docs/html/training/tv/tif/tvinput.jd
@@ -0,0 +1,177 @@
+page.title=Developing a TV Input Service
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#manifest">Declare Your TV Input Service in the Manifest</a></li>
+ <li><a href="#tvinput">Define Your TV Input Service</a></li>
+ <li><a href="#setup">Define Setup and Settings Activities</a></li>
+ </ol>
+ <h2>You should also read</h2>
+ <ul>
+ <li><a href="{@docRoot}reference/android/media/tv/package-summary.html">
+ android.media.tv</a></li>
+ <li><a class="external-lin" href="http://source.android.com/devices/tv/index.html">
+ TV Input Framework</a></li>
+ </ul>
+ <h2>Try It Out</h2>
+ <ul>
+ <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+ TV Input Service sample app</a></li>
+ </ul>
+</div>
+</div>
+
+<p>A TV input service represents a media stream source, and lets you present your media content in a
+linear, broadcast TV fashion as channels and programs. With the TV input service, you can provide
+parental controls, program guide information, and content ratings. The TV input service works
+with the Android system TV app, developed for the device and immutable by third-party apps, which
+ultimately controls and presents content on the TV. See
+<a class="external-link" href="http://source.android.com/devices/tv/index.html">
+TV Input Framework</a> for more information about the framework architecture and its components.</p>
+
+<p>To develop a TV input service, you implement the following components:</p>
+
+<ul>
+ <li>{@link android.media.tv.TvInputService} provides long-running and background availability for
+ the TV input</li>
+ <li>{@link android.media.tv.TvInputService.Session} maintains the TV input state and communicates
+ with the hosting app</li>
+ <li>{@link android.media.tv.TvContract} describes the channels and programs available to the TV
+ input</li>
+ <li>{@link android.media.tv.TvContract.Channels} represents information about a TV channel</li>
+ <li>{@link android.media.tv.TvContract.Programs} describes a TV program with data such as program
+ title and start time</li>
+ <li>{@link android.media.tv.TvTrackInfo} represents an audio, video, or subtitle track</li>
+ <li>{@link android.media.tv.TvContentRating} describes a content rating, allows for custom content
+ rating schemes</li>
+ <li>{@link android.media.tv.TvInputManager} provides an API to the system TV app and manages
+ the interaction with TV inputs and apps</li>
+</ul>
+
+<h2 id="manifest">Declare Your TV Input Service in the Manifest</h2>
+
+<p>Your app manifest must declare your {@link android.media.tv.TvInputService}. Within that
+declaration, specify the {@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the
+service to connect the TV input to the system. A system service (<code>TvInputManagerService</code>)
+performs the binding and has that permission. The system TV app sends requests to TV input services
+via the {@link android.media.tv.TvInputManager} interface. The service declaration must also
+include an intent filter that specifies the {@link android.media.tv.TvInputService}
+as the action to perform with the intent. Also within the service declaration, declare the service
+meta data in a separate XML resource. The service declaration, the intent filter and the service
+meta data are described in the following example.</p>
+
+<pre>
+<service android:name="com.example.sampletvinput.SampleTvInput"
+ android:label="@string/sample_tv_input_label"
+ android:permission="android.permission.BIND_TV_INPUT">
+ <intent-filter>
+ <action android:name="android.media.tv.TvInputService" />
+ </intent-filter>
+ <meta-data android:name="android.media.tv.input"
+ android:resource="@xml/sample_tv_input" />
+</service>
+</pre>
+
+<p>Define the service meta data in separate XML file, as shown in the following example. The service
+meta data must include a setup interface that describes the TV input's initial configuration and
+channel scan. Also, the service meta data may (optionally) describe a settings activity for users to
+modify the TV input's behavior. The service meta data file is located in the XML resources directory
+for your application and must match the name of the resource in the manifest. Using the example
+manifest entries above, you would create an XML file in the location
+<code>res/xml/sample_tv_input.xml</code>, with the following contents:</p>
+
+<pre>
+<tv-input xmlns:android="http://schemas.android.com/apk/res/android"
+ <!-- Required: activity for setting up the input -->
+ android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity"
+ <!-- Optional: activity for controlling the settings -->
+ android:settingsActivity="com.example.sampletvinput.SampleTvInputSettingsActivity" />
+</pre>
+
+<h2 id="tvinput">Define Your TV Input Service</h2>
+
+<div class="figure">
+<img id="tvinputlife" src="{@docRoot}images/tv/tvinput-life.png" alt=""/>
+<p class="img-caption"><strong>Figure 1.</strong>TvInputService lifecycle.</p>
+</div>
+
+<p>For your service, you extend the {@link android.media.tv.TvInputService} class. A
+{@link android.media.tv.TvInputService} implementation is a
+<a href="{@docRoot}guide/components/bound-services.html">bound service</a> where the system service
+(<code>TvInputManagerService</code>) is the client that binds to it. The service life cycle methods
+you need to implement are illustrated in figure 1.</p>
+
+<p>The {@link android.app.Service#onCreate()} method initializes and starts the
+{@link android.os.HandlerThread} which provides a process thread separate from the UI thread to
+handle system-driven actions. In the following example, the {@link android.app.Service#onCreate()}
+method initializes the {@link android.view.accessibility.CaptioningManager} and prepares to handle
+the {@link android.media.tv.TvInputManager#ACTION_BLOCKED_RATINGS_CHANGED}
+and {@link android.media.tv.TvInputManager#ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED} actions. These
+actions describe system intents fired when the user changes the parental control settings, and when
+there is a change on the list of blocked ratings.</p>
+
+<pre>
+@Override
+public void onCreate() {
+ super.onCreate();
+ mHandlerThread = new HandlerThread(getClass()
+ .getSimpleName());
+ mHandlerThread.start();
+ mDbHandler = new Handler(mHandlerThread.getLooper());
+ mHandler = new Handler();
+ mCaptioningManager = (CaptioningManager)
+ getSystemService(Context.CAPTIONING_SERVICE);
+
+ setTheme(android.R.style.Theme_Holo_Light_NoActionBar);
+
+ mSessions = new ArrayList<BaseTvInputSessionImpl>();
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(TvInputManager
+ .ACTION_BLOCKED_RATINGS_CHANGED);
+ intentFilter.addAction(TvInputManager
+ .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
+ registerReceiver(mBroadcastReceiver, intentFilter);
+}
+</pre>
+
+<p> See <a href="{@docRoot}training/tv/tif/ui.html#control">
+Control Content</a> for more information about working with blocked content and providing
+parental control. See {@link android.media.tv.TvInputManager} for more system-driven actions that
+you may want to handle in your TV input service.</p>
+
+<p>The {@link android.media.tv.TvInputService} creates a
+{@link android.media.tv.TvInputService.Session} that implements {@link android.os.Handler.Callback}
+to handle player state changes. With {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()},
+the {@link android.media.tv.TvInputService.Session} sets the {@link android.view.Surface} with the
+video content. See <a href="{@docRoot}training/tv/tif/ui.html#surface">Integrate Player with Surface</a>
+for more information about working with {@link android.view.Surface} to render video.</p>
+
+<p>The {@link android.media.tv.TvInputService.Session} handles the
+{@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) onTune()}
+event when the user selects a channel, and notifies the system TV app for changes in the content and
+content meta data. These <code>notify()</code>code> methods are described in
+<a href="{@docRoot}training/tv/tif/ui.html#control">
+Control Content</a> and <a href="training/tv/tif/ui.html#track">Handle Track Selection</a> further
+in this training.</p>
+
+<h2 id="setup">Define Setup and Settings Activities</h2>
+
+<p>The system TV app works with the setup and settings activities you define for your TV input. The
+setup activity is required and must provide at least one channel record for the system database. The
+system TV app will invoke the setup activity when it cannot find a channel for the TV input.
+<p>The setup activity describes to the system TV app the channels made available through the TV
+input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating
+and Updating Channel Data</a>.</p>
+
+<p>The settings activity is optional. You can define a settings activity to turn on parental
+controls, enable closed captions, set the display attributes, and so forth.</p>
+
+
diff --git a/docs/html/training/tv/tif/ui.jd b/docs/html/training/tv/tif/ui.jd
new file mode 100644
index 0000000..6ead3db
--- /dev/null
+++ b/docs/html/training/tv/tif/ui.jd
@@ -0,0 +1,304 @@
+page.title=Managing User Interaction
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+ <h2>This lesson teaches you to</h2>
+ <ol>
+ <li><a href="#surface">Integrate Player with Surface</a></li>
+ <li><a href="#overlay">Use an Overlay</a></li>
+ <li><a href="#control">Control Content</a></li>
+ <li><a href="#track">Handle Track Selection</a></li>
+ </ol>
+ <h2>Try It Out</h2>
+ <ul>
+ <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+ TV Input Service sample app</a></li>
+ </ul>
+</div>
+</div>
+
+<p>In the live TV experience the user changes channels and is presented with
+channel and program information briefly before the information disappears. Other types of information,
+such as messages ("DO NOT ATTEMPT AT HOME"), subtitles, or ads may need to persist. As with any TV
+app, such information should not interfere with the program content playing on the screen.</p>
+
+<img src="{@docRoot}images/tv/do-not-attempt.png" id="figure1">
+<p class="img-caption">
+ <strong>Figure 1.</strong> An overlay message in a live TV app.
+</p>
+
+<p>Also consider whether certain program content should be presented, given the
+content's rating and parental control settings, and how your app behaves and informs the user when
+content is blocked or unavailable. This lesson describes how to develop your TV input's user
+experience for these considerations.</p>
+
+<h2 id="surface">Integrate Player with Surface</h2>
+
+<p>Your TV input must render video onto a {@link android.view.Surface} object, which is passed by
+the {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) TvInputService.Session.onSetSurface()}
+method. Here's an example of how to use a {@link android.media.MediaPlayer} instance for playing
+content in the {@link android.view.Surface} object:</p>
+
+<pre>
+@Override
+public boolean onSetSurface(Surface surface) {
+ if (mPlayer != null) {
+ mPlayer.setSurface(surface);
+ }
+ mSurface = surface;
+ return true;
+}
+
+@Override
+public void onSetStreamVolume(float volume) {
+ if (mPlayer != null) {
+ mPlayer.setVolume(volume, volume);
+ }
+ mVolume = volume;
+}
+</pre>
+
+<p>Similarly, here's how to do it using <a href="{@docRoot}guide/topics/media/exoplayer.html">
+ExoPlayer</a>:</p>
+
+<pre>
+@Override
+public boolean onSetSurface(Surface surface) {
+ if (mPlayer != null) {
+ mPlayer.sendMessage(mVideoRenderer,
+ MediaCodecVideoTrackRenderer.MSG_SET_SURFACE,
+ surface);
+ }
+ mSurface = surface;
+ return true;
+}
+
+@Override
+public void onSetStreamVolume(float volume) {
+ if (mPlayer != null) {
+ mPlayer.sendMessage(mAudioRenderer,
+ MediaCodecAudioTrackRenderer.MSG_SET_VOLUME,
+ volume);
+ }
+ mVolume = volume;
+}
+</pre>
+
+<h2 id="overlay">Use an Overlay</h2>
+
+<p>Use an overlay to display subtitles, messages, ads or MHEG-5 data broadcasts. By default, the
+overlay is disabled. You can enable it when you create the session by calling
+{@link android.media.tv.TvInputService.Session#setOverlayViewEnabled(boolean) TvInputService.Session.setOverlayViewEnabled(true)},
+as in the following example:</p>
+
+<pre>
+@Override
+public final Session onCreateSession(String inputId) {
+ BaseTvInputSessionImpl session = onCreateSessionInternal(inputId);
+ session.setOverlayViewEnabled(true);
+ mSessions.add(session);
+ return session;
+}
+</pre>
+
+<p>Use a {@link android.view.View} object for the overlay, returned from {@link android.media.tv.TvInputService.Session#onCreateOverlayView() TvInputService.Session.onCreateOverlayView()}, as shown here:</p>
+
+<pre>
+@Override
+public View onCreateOverlayView() {
+ LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+ View view = inflater.inflate(R.layout.overlayview, null);
+ mSubtitleView = (SubtitleView) view.findViewById(R.id.subtitles);
+
+ // Configure the subtitle view.
+ CaptionStyleCompat captionStyle;
+ float captionTextSize = getCaptionFontSize();
+ captionStyle = CaptionStyleCompat.createFromCaptionStyle(
+ mCaptioningManager.getUserStyle());
+ captionTextSize *= mCaptioningManager.getFontScale();
+ mSubtitleView.setStyle(captionStyle);
+ mSubtitleView.setTextSize(captionTextSize);
+ return view;
+}
+</pre>
+
+<p>The layout definition for the overlay might look something like this:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.google.android.exoplayer.text.SubtitleView
+ android:id="@+id/subtitles"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
+ android:layout_marginBottom="32dp"
+ android:visibility="invisible"/>
+</FrameLayout>
+</pre>
+
+<h2 id="control">Control Content</h2>
+
+<p>When the user selects a channel, your TV input handles the {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri)
+onTune()} callback in the {@link android.media.tv.TvInputService.Session} object. The system TV
+app's parental controls determine what content displays, given the content rating.
+The following sections describe how to manage channel and program selection using the
+{@link android.media.tv.TvInputService.Session} <code>notify</code> methods that
+communicate with the system TV app.</p>
+
+<h3 id="unavailable">Make Video Unavailable</h3>
+
+<p>When the user changes the channel, you want to make sure the screen doesn't display any stray
+video artifacts before your TV input renders the content. When you call {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) TvInputService.Session.onTune()},
+you can prevent the video from being presented by calling {@link android.media.tv.TvInputService.Session#notifyVideoUnavailable(int) TvInputService.Session.notifyVideoUnavailable()}
+and passing the {@link android.media.tv.TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING} constant, as
+shown in the following example.</p>
+
+<pre>
+@Override
+public boolean onTune(Uri channelUri) {
+ if (mSubtitleView != null) {
+ mSubtitleView.setVisibility(View.INVISIBLE);
+ }
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
+ mUnblockedRatingSet.clear();
+
+ mDbHandler.removeCallbacks(mPlayCurrentProgramRunnable);
+ mPlayCurrentProgramRunnable = new PlayCurrentProgramRunnable(channelUri);
+ mDbHandler.post(mPlayCurrentProgramRunnable);
+ return true;
+}
+</pre>
+
+<p>Then, when the content is rendered to the {@link android.view.Surface}, you call
+{@link android.media.tv.TvInputService.Session#notifyVideoAvailable() TvInputService.Session.notifyVideoAvailable()}
+to allow the video to display, like so:</p>
+
+<pre>
+@Override
+public void onDrawnToSurface(Surface surface) {
+ mFirstFrameDrawn = true;
+ notifyVideoAvailable();
+}
+</pre>
+
+<p>This transition lasts only for fractions of a second, but presenting a blank screen is
+visually better than allowing the picture to flash odd blips and jitters.</p>
+
+<p>See also, <a href="#surface">Integrate Player with Surface</a> for more information about working
+with {@link android.view.Surface} to render video.</p>
+
+<h3 id="parental">Provide Parental Control</h3>
+
+<p>To determine if a given content is blocked by parental controls and content rating, you check the
+{@link android.media.tv.TvInputManager} class methods, {@link android.media.tv.TvInputManager#isParentalControlsEnabled()}
+and {@link android.media.tv.TvInputManager#isRatingBlocked(android.media.tv.TvContentRating)}. You
+might also want to make sure the content's {@link android.media.tv.TvContentRating} is included in a
+set of currently allowed content ratings. These considerations are shown in the following sample.</p>
+
+<pre>
+private void checkContentBlockNeeded() {
+ if (mCurrentContentRating == null || !mTvInputManager.isParentalControlsEnabled()
+ || !mTvInputManager.isRatingBlocked(mCurrentContentRating)
+ || mUnblockedRatingSet.contains(mCurrentContentRating)) {
+ // Content rating is changed so we don't need to block anymore.
+ // Unblock content here explicitly to resume playback.
+ unblockContent(null);
+ return;
+ }
+
+ mLastBlockedRating = mCurrentContentRating;
+ if (mPlayer != null) {
+ // Children restricted content might be blocked by TV app as well,
+ // but TIF should do its best not to show any single frame of blocked content.
+ releasePlayer();
+ }
+
+ notifyContentBlocked(mCurrentContentRating);
+}
+</pre>
+
+<p>Once you have determined if the content should or should not be blocked, notify the system TV
+app by calling the
+{@link android.media.tv.TvInputService.Session} method {@link android.media.tv.TvInputService.Session#notifyContentAllowed() notifyContentAllowed()}
+or
+{@link android.media.tv.TvInputService.Session#notifyContentBlocked(android.media.tv.TvContentRating) notifyContentBlocked()}
+, as shown in the previous example.</p>
+
+<p>Use the {@link android.media.tv.TvContentRating} class to generate the system-defined string for
+the {@link android.media.tv.TvContract.Programs#COLUMN_CONTENT_RATING} with the
+<code><a href="{@docRoot}reference/android/media/tv/TvContentRating.html#createRating(java.lang.String, java.lang.String, java.lang.String, java.lang.String...)">TvContentRating.createRating()</a></code>
+method, as shown here:</p>
+
+<pre>
+TvContentRating rating = TvContentRating.createRating(
+ "com.android.tv",
+ "US_TV",
+ "US_TV_PG",
+ "US_TV_D", "US_TV_L");
+</pre>
+
+<h2 id="track">Handle Track Selection</h2>
+
+<p>The {@link android.media.tv.TvTrackInfo} class holds information about media tracks such
+as the track type (video, audio, or subtitle) and so forth. </p>
+
+<p>The first time your TV input session is able to get track information, it should call
+<code><a href="{@docRoot}reference/android/media/tv/TvInputService.Session.html#notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>)">TvInputService.Session.notifyTracksChanged()</a></code> with a list of all tracks to update the system TV app. When there
+is a change in track information, call
+<code><a href="{@docRoot}reference/android/media/tv/TvInputService.Session.html#notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>)">notifyTracksChanged()</a></code>
+again to update the system.
+
+</p>
+
+<p>The system TV app provides an interface for the user to select a specific track if more than one
+track is available for a given track type; for example, subtitles in different languages. Your TV
+input responds to the
+{@link android.media.tv.TvInputService.Session#onSelectTrack(int, java.lang.String) onSelectTrack()}
+call from the system TV app by calling
+{@link android.media.tv.TvInputService.Session#notifyTrackSelected(int, java.lang.String) notifyTrackSelected()}
+, as shown in the following example. Note that when <code>null</code>
+is passed as the track ID, this <em>deselects</em> the track.</p>
+
+<pre>
+@Override
+public boolean onSelectTrack(int type, String trackId) {
+ if (mPlayer != null) {
+ if (type == TvTrackInfo.TYPE_SUBTITLE) {
+ if (!mCaptionEnabled && trackId != null) {
+ return false;
+ }
+ mSelectedSubtitleTrackId = trackId;
+ if (trackId == null) {
+ mSubtitleView.setVisibility(View.INVISIBLE);
+ }
+ }
+ if (mPlayer.selectTrack(type, trackId)) {
+ notifyTrackSelected(type, trackId);
+ return true;
+ }
+ }
+ return false;
+}
+</pre>
+
+
+
+
+
+
+
diff --git a/docs/html/training/wearables/apps/voice.jd b/docs/html/training/wearables/apps/voice.jd
index 6d49319..3aef3c4 100644
--- a/docs/html/training/wearables/apps/voice.jd
+++ b/docs/html/training/wearables/apps/voice.jd
@@ -131,6 +131,17 @@
</tr>
<tr>
+ <td>Start stopwatch</td>
+ <td>"Ok Google, start stopwatch"</td>
+ <td>
+ <dl>
+ <dt>Action</dt>
+ <dd><code>com.google.android.wearable.action.STOPWATCH</code></dd>
+ </dl>
+ </td>
+ </tr>
+
+ <tr>
<td>Start/Stop a bike ride</td>
<td>"OK Google, start cycling"<br/><br/>"OK Google, start my bike ride"<br/><br/>"OK Google, stop cycling"</td>
<td>
diff --git a/docs/html/training/wearables/watch-faces/drawing.jd b/docs/html/training/wearables/watch-faces/drawing.jd
index 3c5da34..60da5d5 100644
--- a/docs/html/training/wearables/watch-faces/drawing.jd
+++ b/docs/html/training/wearables/watch-faces/drawing.jd
@@ -377,7 +377,8 @@
<ul>
<li>For devices that use low-bit ambient mode, the screen supports fewer bits for each color
-in ambient mode, so you should disable anti-aliasing.</li>
+in ambient mode, so you should disable anti-aliasing and bitmap filtering when the device switches
+to ambient mode.</li>
<li>For devices that require burn-in protection, avoid using large blocks of white pixels in
ambient mode and do not place content within 10 pixels of the edge of the screen, since the
system shifts the content periodically to avoid pixel burn-in.</li>
@@ -385,7 +386,9 @@
<p>For more information about low-bit ambient mode and burn-in protection, see
<a href="{@docRoot}design/wear/watchfaces.html#SpecialScreens">Optimize for Special
-Screens</a>.</p>
+Screens</a>. For more information on how to disable bitmap filtering, see
+<a href="{@docRoot}training/wearables/watch-faces/performance.html#BitmapFiltering">Bitmap
+Filtering</a>.</p>
<h2 id="Modes">Respond to Changes Between Modes</h2>
diff --git a/docs/html/training/wearables/watch-faces/performance.jd b/docs/html/training/wearables/watch-faces/performance.jd
index 68438fe..118bc6a 100644
--- a/docs/html/training/wearables/watch-faces/performance.jd
+++ b/docs/html/training/wearables/watch-faces/performance.jd
@@ -99,7 +99,9 @@
setFilterBitmap()} method. <a href="#fig2">Figure 2</a> shows a magnified view of a clock hand with
and without bitmap filtering.</p>
-
+<p class="note"><strong>Note:</strong> In low-bit ambient mode, the system does not reliably
+render the colors in the image for bitmap filtering to process successfully. When ambient mode is
+active, disable bitmap filtering.</p>
<h2 id="OutDrawing">Move Expensive Operations Outside the Drawing Method</h2>
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 49c4247..c63c8ba 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -356,6 +356,108 @@
public static final int RAW10 = 0x25;
/**
+ * <p>
+ * Android 12-bit raw format
+ * </p>
+ * <p>
+ * This is a single-plane, 12-bit per pixel, densely packed (in each row),
+ * unprocessed format, usually representing raw Bayer-pattern images coming
+ * from an image sensor.
+ * </p>
+ * <p>
+ * In an image buffer with this format, starting from the first pixel of each
+ * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first
+ * and second byte contains the top 8 bits of first and second pixel. The third
+ * byte contains the 4 least significant bits of the two pixels, the exact layout
+ * data for each two consecutive pixels is illustrated below (Pi[j] stands for
+ * the jth bit of the ith pixel):
+ * </p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="center"></th>
+ * <th align="center">bit 7</th>
+ * <th align="center">bit 6</th>
+ * <th align="center">bit 5</th>
+ * <th align="center">bit 4</th>
+ * <th align="center">bit 3</th>
+ * <th align="center">bit 2</th>
+ * <th align="center">bit 1</th>
+ * <th align="center">bit 0</th>
+ * </tr>
+ * </thead> <tbody>
+ * <tr>
+ * <td align="center">Byte 0:</td>
+ * <td align="center">P0[11]</td>
+ * <td align="center">P0[10]</td>
+ * <td align="center">P0[ 9]</td>
+ * <td align="center">P0[ 8]</td>
+ * <td align="center">P0[ 7]</td>
+ * <td align="center">P0[ 6]</td>
+ * <td align="center">P0[ 5]</td>
+ * <td align="center">P0[ 4]</td>
+ * </tr>
+ * <tr>
+ * <td align="center">Byte 1:</td>
+ * <td align="center">P1[11]</td>
+ * <td align="center">P1[10]</td>
+ * <td align="center">P1[ 9]</td>
+ * <td align="center">P1[ 8]</td>
+ * <td align="center">P1[ 7]</td>
+ * <td align="center">P1[ 6]</td>
+ * <td align="center">P1[ 5]</td>
+ * <td align="center">P1[ 4]</td>
+ * </tr>
+ * <tr>
+ * <td align="center">Byte 2:</td>
+ * <td align="center">P1[ 3]</td>
+ * <td align="center">P1[ 2]</td>
+ * <td align="center">P1[ 1]</td>
+ * <td align="center">P1[ 0]</td>
+ * <td align="center">P0[ 3]</td>
+ * <td align="center">P0[ 2]</td>
+ * <td align="center">P0[ 1]</td>
+ * <td align="center">P0[ 0]</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>
+ * This format assumes
+ * <ul>
+ * <li>a width multiple of 4 pixels</li>
+ * <li>an even height</li>
+ * </ul>
+ * </p>
+ *
+ * <pre>size = row stride * height</pre> where the row stride is in <em>bytes</em>,
+ * not pixels.
+ *
+ * <p>
+ * Since this is a densely packed format, the pixel stride is always 0. The
+ * application must use the pixel data layout defined in above table to
+ * access each row data. When row stride is equal to {@code width * (12 / 8)}, there
+ * will be no padding bytes at the end of each row, the entire image data is
+ * densely packed. When stride is larger than {@code width * (12 / 8)}, padding
+ * bytes will be present at the end of each row.
+ * </p>
+ * <p>
+ * For example, the {@link android.media.Image} object can provide data in
+ * this format from a {@link android.hardware.camera2.CameraDevice} (if
+ * supported) through a {@link android.media.ImageReader} object. The
+ * {@link android.media.Image#getPlanes() Image#getPlanes()} will return a
+ * single plane containing the pixel data. The pixel stride is always 0 in
+ * {@link android.media.Image.Plane#getPixelStride()}, and the
+ * {@link android.media.Image.Plane#getRowStride()} describes the vertical
+ * neighboring pixel distance (in bytes) between adjacent rows.
+ * </p>
+ *
+ * @see android.media.Image
+ * @see android.media.ImageReader
+ * @see android.hardware.camera2.CameraDevice
+ */
+ public static final int RAW12 = 0x26;
+
+ /**
* Android dense depth image format.
*
* Each pixel is 16 bits, representing a depth ranging measurement from
@@ -388,6 +490,33 @@
public static final int DEPTH_POINT_CLOUD = 0x101;
/**
+ * Android private opaque image format.
+ * <p>
+ * The choices of the actual format and pixel data layout are entirely up to
+ * the device-specific and framework internal implementations, and may vary
+ * depending on use cases even for the same device. The buffers of this
+ * format can be produced by components like
+ * {@link android.media.ImageWriter ImageWriter} , and interpreted correctly
+ * by consumers like {@link android.hardware.camera2.CameraDevice
+ * CameraDevice} based on the device/framework private information. However,
+ * these buffers are not directly accessible to the application.
+ * </p>
+ * <p>
+ * When an {@link android.media.Image Image} of this format is obtained from
+ * an {@link android.media.ImageReader ImageReader} or
+ * {@link android.media.ImageWriter ImageWriter}, the
+ * {@link android.media.Image#getPlanes() getPlanes()} method will return an
+ * empty {@link android.media.Image.Plane Plane} array.
+ * </p>
+ * <p>
+ * If a buffer of this format is to be used as an OpenGL ES texture, the
+ * framework will assume that sampling the texture will always return an
+ * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values).
+ * </p>
+ */
+ public static final int PRIVATE = 0x22;
+
+ /**
* Use this function to retrieve the number of bits per pixel of an
* ImageFormat.
*
@@ -418,6 +547,8 @@
return 16;
case RAW10:
return 10;
+ case RAW12:
+ return 12;
}
return -1;
}
@@ -445,8 +576,10 @@
case YUV_420_888:
case RAW_SENSOR:
case RAW10:
+ case RAW12:
case DEPTH16:
case DEPTH_POINT_CLOUD:
+ case PRIVATE:
return true;
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1da198c..d3cb9b1 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -2120,9 +2120,9 @@
int contextLen = contextEnd - contextStart;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
- int result = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
+ int relPos = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
TemporaryBuffer.recycle(buf);
- return result;
+ return (relPos == -1) ? -1 : relPos + contextStart;
}
/**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 56876e94..e8b8c77 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -816,9 +816,12 @@
* returned. You can use the method {@link #resolveOpacity} to perform a
* standard reduction of two opacities to the appropriate single output.
*
- * <p>Note that the returned value does <em>not</em> take into account a
+ * <p>Note that the returned value does not necessarily take into account a
* custom alpha or color filter that has been applied by the client through
- * the {@link #setAlpha} or {@link #setColorFilter} methods.
+ * the {@link #setAlpha} or {@link #setColorFilter} methods. Some subclasses,
+ * such as {@link BitmapDrawable}, {@link ColorDrawable}, and {@link GradientDrawable},
+ * do account for the value of {@link #setAlpha}, but the general behavior is dependent
+ * upon the implementation of the subclass.
*
* @return int The opacity class of the Drawable.
*
diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
index a6836a8..ed83314 100644
--- a/include/android_runtime/android_view_Surface.h
+++ b/include/android_runtime/android_view_Surface.h
@@ -43,6 +43,7 @@
NV21 = 0x11,
YUY2 = 0x14,
RAW_SENSOR = 0x20,
+ PRIVATE = 0x22,
YUV_420_888 = 0x23,
RAW10 = 0x25,
JPEG = 0x100,
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index f3eb317..0bd1dbd 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -457,7 +457,7 @@
String keyAlgorithmString = key.getAlgorithm();
@KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
- @KeyStoreKeyConstraints.AlgorithmEnum Integer digest;
+ @KeyStoreKeyConstraints.DigestEnum Integer digest;
try {
keyAlgorithm =
KeyStoreKeyConstraints.Algorithm.fromJCASecretKeyAlgorithm(keyAlgorithmString);
@@ -493,6 +493,19 @@
if (digest != null) {
args.addInt(KeymasterDefs.KM_TAG_DIGEST,
KeyStoreKeyConstraints.Digest.toKeymaster(digest));
+ Integer digestOutputSizeBytes =
+ KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
+ if (digestOutputSizeBytes != null) {
+ // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
+ // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
+ args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
+ }
+ }
+ if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
+ if (digest == null) {
+ throw new IllegalStateException("Digest algorithm must be specified for key"
+ + " algorithm " + keyAlgorithmString);
+ }
}
@KeyStoreKeyConstraints.PurposeEnum int purposes = (params.getPurposes() != null)
@@ -523,30 +536,37 @@
if (params.getUserAuthenticators().isEmpty()) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
} else {
- // TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized
-// for (int userAuthenticatorId : params.getUserAuthenticators()) {
-// args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId);
-// }
+ args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
+ KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+ params.getUserAuthenticators()));
+ }
+ if (params.isInvalidatedOnNewFingerprintEnrolled()) {
+ // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
+ // that.
}
if (params.getUserAuthenticationValidityDurationSeconds() != null) {
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
params.getUserAuthenticationValidityDurationSeconds());
}
- if (params.getKeyValidityStart() != null) {
- args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, params.getKeyValidityStart());
- }
- if (params.getKeyValidityForOriginationEnd() != null) {
- args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- params.getKeyValidityForOriginationEnd());
- }
- if (params.getKeyValidityForConsumptionEnd() != null) {
- args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- params.getKeyValidityForConsumptionEnd());
- }
+ args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
+ (params.getKeyValidityStart() != null)
+ ? params.getKeyValidityStart() : new Date(0));
+ args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+ (params.getKeyValidityForOriginationEnd() != null)
+ ? params.getKeyValidityForOriginationEnd() : new Date(Long.MAX_VALUE));
+ args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+ (params.getKeyValidityForConsumptionEnd() != null)
+ ? params.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
// TODO: Remove this once keymaster does not require us to specify the size of imported key.
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8);
+ if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+ || ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) {
+ // Permit caller-specified IV. This is needed for the Cipher abstraction.
+ args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
+ }
+
Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias);
String keyAliasInKeystore = Credentials.USER_SECRET_KEY + entryAlias;
int errorCode = mKeyStore.importKey(
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index 598bcd8..a7c2ddb 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -16,8 +16,12 @@
package android.security;
+import java.lang.reflect.Method;
import java.security.Provider;
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+
/**
* A provider focused on providing JCA interfaces for the Android KeyStore.
*
@@ -39,5 +43,74 @@
// javax.crypto.KeyGenerator
put("KeyGenerator.AES", KeyStoreKeyGeneratorSpi.AES.class.getName());
put("KeyGenerator.HmacSHA256", KeyStoreKeyGeneratorSpi.HmacSHA256.class.getName());
+
+ // java.security.SecretKeyFactory
+ put("SecretKeyFactory.AES", KeyStoreSecretKeyFactorySpi.class.getName());
+ put("SecretKeyFactory.HmacSHA256", KeyStoreSecretKeyFactorySpi.class.getName());
+
+ // javax.crypto.Mac
+ putMacImpl("HmacSHA256", KeyStoreHmacSpi.HmacSHA256.class.getName());
+
+ // javax.crypto.Cipher
+ putSymmetricCipherImpl("AES/ECB/NoPadding",
+ KeyStoreCipherSpi.AES.ECB.NoPadding.class.getName());
+ putSymmetricCipherImpl("AES/ECB/PKCS7Padding",
+ KeyStoreCipherSpi.AES.ECB.PKCS7Padding.class.getName());
+
+ putSymmetricCipherImpl("AES/CBC/NoPadding",
+ KeyStoreCipherSpi.AES.CBC.NoPadding.class.getName());
+ putSymmetricCipherImpl("AES/CBC/PKCS7Padding",
+ KeyStoreCipherSpi.AES.CBC.PKCS7Padding.class.getName());
+
+ putSymmetricCipherImpl("AES/CTR/NoPadding",
+ KeyStoreCipherSpi.AES.CTR.NoPadding.class.getName());
+ }
+
+ private void putMacImpl(String algorithm, String implClass) {
+ put("Mac." + algorithm, implClass);
+ put("Mac." + algorithm + " SupportedKeyClasses", KeyStoreSecretKey.class.getName());
+ }
+
+ private void putSymmetricCipherImpl(String transformation, String implClass) {
+ put("Cipher." + transformation, implClass);
+ put("Cipher." + transformation + " SupportedKeyClasses", KeyStoreSecretKey.class.getName());
+ }
+
+ /**
+ * Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
+ * primitive.
+ *
+ * <p>The following primitives are supported: {@link Cipher} and {@link Mac}.
+ *
+ * @return KeyStore operation handle or {@code null} if the provided primitive's KeyStore
+ * operation is not in progress.
+ *
+ * @throws IllegalArgumentException if the provided primitive is not supported or is not backed
+ * by AndroidKeyStore provider.
+ */
+ public static Long getKeyStoreOperationHandle(Object cryptoPrimitive) {
+ if (cryptoPrimitive == null) {
+ throw new NullPointerException();
+ }
+ if ((!(cryptoPrimitive instanceof Mac)) && (!(cryptoPrimitive instanceof Cipher))) {
+ throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive);
+ }
+ Object spi;
+ // TODO: Replace this Reflection based codewith direct invocations once the libcore changes
+ // are in.
+ try {
+ Method getSpiMethod = cryptoPrimitive.getClass().getDeclaredMethod("getSpi");
+ getSpiMethod.setAccessible(true);
+ spi = getSpiMethod.invoke(cryptoPrimitive);
+ } catch (ReflectiveOperationException e) {
+ throw new IllegalArgumentException(
+ "Unsupported crypto primitive: " + cryptoPrimitive, e);
+ }
+ if (!(spi instanceof KeyStoreCryptoOperation)) {
+ throw new IllegalArgumentException(
+ "Crypto primitive not backed by Android KeyStore: " + cryptoPrimitive
+ + ", spi: " + spi);
+ }
+ return ((KeyStoreCryptoOperation) spi).getOperationHandle();
}
}
diff --git a/keystore/java/android/security/CryptoOperationException.java b/keystore/java/android/security/CryptoOperationException.java
index ce64455..00c142f 100644
--- a/keystore/java/android/security/CryptoOperationException.java
+++ b/keystore/java/android/security/CryptoOperationException.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.security;
/**
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
index 6274b70..02b0816 100644
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ b/keystore/java/android/security/KeyGeneratorSpec.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.security;
import android.content.Context;
@@ -43,6 +59,7 @@
private final Integer mMaxUsesPerBoot;
private final Set<Integer> mUserAuthenticators;
private final Integer mUserAuthenticationValidityDurationSeconds;
+ private final boolean mInvalidatedOnNewFingerprintEnrolled;
private KeyGeneratorSpec(
Context context,
@@ -58,7 +75,8 @@
Integer minSecondsBetweenOperations,
Integer maxUsesPerBoot,
Set<Integer> userAuthenticators,
- Integer userAuthenticationValidityDurationSeconds) {
+ Integer userAuthenticationValidityDurationSeconds,
+ boolean invalidatedOnNewFingerprintEnrolled) {
if (context == null) {
throw new IllegalArgumentException("context == null");
} else if (TextUtils.isEmpty(keyStoreAlias)) {
@@ -85,6 +103,7 @@
? new HashSet<Integer>(userAuthenticators)
: Collections.<Integer>emptySet();
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
}
/**
@@ -146,7 +165,7 @@
}
/**
- * Gets the set of purposes for which the key can be used to the provided set of purposes.
+ * Gets the set of purposes for which the key can be used.
*
* @return set of purposes or {@code null} if the key can be used for any purpose.
*/
@@ -223,6 +242,19 @@
}
/**
+ * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+ * enrolled. This constraint only has effect if fingerprint reader is one of the user
+ * authenticators protecting access to this key.
+ *
+ * @see #getUserAuthenticators()
+ *
+ * @hide
+ */
+ public boolean isInvalidatedOnNewFingerprintEnrolled() {
+ return mInvalidatedOnNewFingerprintEnrolled;
+ }
+
+ /**
* Returns {@code true} if the key must be encrypted in the {@link java.security.KeyStore}.
*/
public boolean isEncryptionRequired() {
@@ -244,6 +276,7 @@
private Integer mMaxUsesPerBoot;
private Set<Integer> mUserAuthenticators;
private Integer mUserAuthenticationValidityDurationSeconds;
+ private boolean mInvalidatedOnNewFingerprintEnrolled;
/**
* Creates a new instance of the {@code Builder} with the given {@code context}. The
@@ -457,6 +490,22 @@
}
/**
+ * Sets whether this key must be invalidated (permanently) once a new fingerprint is
+ * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+ * protecting access to the key.
+ *
+ * <p>By default, enrolling a new fingerprint does not invalidate the key.
+ *
+ * @see #setUserAuthenticators(Set)
+ *
+ * @hide
+ */
+ public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+ mInvalidatedOnNewFingerprintEnrolled = invalidated;
+ return this;
+ }
+
+ /**
* Builds a new instance instance of {@code KeyGeneratorSpec}.
*
* @throws IllegalArgumentException if a required field is missing or violates a constraint.
@@ -465,7 +514,8 @@
return new KeyGeneratorSpec(mContext, mKeystoreAlias, mFlags, mKeySize,
mKeyValidityStart, mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd,
mPurposes, mPadding, mBlockMode, mMinSecondsBetweenOperations, mMaxUsesPerBoot,
- mUserAuthenticators, mUserAuthenticationValidityDurationSeconds);
+ mUserAuthenticators, mUserAuthenticationValidityDurationSeconds,
+ mInvalidatedOnNewFingerprintEnrolled);
}
}
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index f68b3f6..94a479b 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -476,4 +476,34 @@
return SYSTEM_ERROR;
}
}
+
+ /**
+ * Check if the operation referenced by {@code token} is currently authorized.
+ *
+ * @param token An operation token returned by a call to {@link KeyStore.begin}.
+ */
+ public boolean isOperationAuthorized(IBinder token) {
+ try {
+ return mBinder.isOperationAuthorized(token);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return false;
+ }
+ }
+
+ /**
+ * Add an authentication record to the keystore authorization table.
+ *
+ * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
+ * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
+ * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
+ */
+ public int addAuthToken(byte[] authToken) {
+ try {
+ return mBinder.addAuthToken(authToken);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return SYSTEM_ERROR;
+ }
+ }
}
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
new file mode 100644
index 0000000..5219086
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.os.IBinder;
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterDefs;
+import android.security.keymaster.OperationResult;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Arrays;
+
+import javax.crypto.AEADBadTagException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Base class for {@link CipherSpi} providing Android KeyStore backed ciphers.
+ *
+ * @hide
+ */
+public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCryptoOperation {
+
+ public abstract static class AES extends KeyStoreCipherSpi {
+ protected AES(@KeyStoreKeyConstraints.BlockModeEnum int blockMode,
+ @KeyStoreKeyConstraints.PaddingEnum int padding, boolean ivUsed) {
+ super(KeyStoreKeyConstraints.Algorithm.AES,
+ blockMode,
+ padding,
+ 16,
+ ivUsed);
+ }
+
+ public abstract static class ECB extends AES {
+ protected ECB(@KeyStoreKeyConstraints.PaddingEnum int padding) {
+ super(KeyStoreKeyConstraints.BlockMode.ECB, padding, false);
+ }
+
+ public static class NoPadding extends ECB {
+ public NoPadding() {
+ super(KeyStoreKeyConstraints.Padding.NONE);
+ }
+ }
+
+ public static class PKCS7Padding extends ECB {
+ public PKCS7Padding() {
+ super(KeyStoreKeyConstraints.Padding.PKCS7);
+ }
+ }
+ }
+
+ public abstract static class CBC extends AES {
+ protected CBC(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
+ super(KeyStoreKeyConstraints.BlockMode.CBC, padding, true);
+ }
+
+ public static class NoPadding extends CBC {
+ public NoPadding() {
+ super(KeyStoreKeyConstraints.Padding.NONE);
+ }
+ }
+
+ public static class PKCS7Padding extends CBC {
+ public PKCS7Padding() {
+ super(KeyStoreKeyConstraints.Padding.PKCS7);
+ }
+ }
+ }
+
+ public abstract static class CTR extends AES {
+ protected CTR(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
+ super(KeyStoreKeyConstraints.BlockMode.CTR, padding, true);
+ }
+
+ public static class NoPadding extends CTR {
+ public NoPadding() {
+ super(KeyStoreKeyConstraints.Padding.NONE);
+ }
+ }
+ }
+ }
+
+ private final KeyStore mKeyStore;
+ private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
+ private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode;
+ private final @KeyStoreKeyConstraints.PaddingEnum int mPadding;
+ private final int mBlockSizeBytes;
+ private final boolean mIvUsed;
+
+ // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
+ // doFinal finishes.
+ protected boolean mEncrypting;
+ private KeyStoreSecretKey mKey;
+ private SecureRandom mRng;
+ private boolean mFirstOperationInitiated;
+ byte[] mIv;
+
+ // Fields below must be reset
+ private byte[] mAdditionalEntropyForBegin;
+ /**
+ * Token referencing this operation inside keystore service. It is initialized by
+ * {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and one some
+ * error conditions in between.
+ */
+ private IBinder mOperationToken;
+ private Long mOperationHandle;
+ private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;
+
+ protected KeyStoreCipherSpi(
+ @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
+ @KeyStoreKeyConstraints.BlockModeEnum int blockMode,
+ @KeyStoreKeyConstraints.PaddingEnum int padding,
+ int blockSizeBytes,
+ boolean ivUsed) {
+ mKeyStore = KeyStore.getInstance();
+ mAlgorithm = algorithm;
+ mBlockMode = blockMode;
+ mPadding = padding;
+ mBlockSizeBytes = blockSizeBytes;
+ mIvUsed = ivUsed;
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
+ init(opmode, key, random);
+ initAlgorithmSpecificParameters();
+ ensureKeystoreOperationInitialized();
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ init(opmode, key, random);
+ initAlgorithmSpecificParameters(params);
+ ensureKeystoreOperationInitialized();
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+ init(opmode, key, random);
+ initAlgorithmSpecificParameters(params);
+ ensureKeystoreOperationInitialized();
+ }
+
+ private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
+ reset();
+ if (!(key instanceof KeyStoreSecretKey)) {
+ throw new InvalidKeyException(
+ "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
+ }
+ mKey = (KeyStoreSecretKey) key;
+ mRng = random;
+ mIv = null;
+ mFirstOperationInitiated = false;
+
+ if ((opmode != Cipher.ENCRYPT_MODE) && (opmode != Cipher.DECRYPT_MODE)) {
+ throw new UnsupportedOperationException(
+ "Only ENCRYPT and DECRYPT modes supported. Mode: " + opmode);
+ }
+ mEncrypting = opmode == Cipher.ENCRYPT_MODE;
+ }
+
+ private void reset() {
+ IBinder operationToken = mOperationToken;
+ if (operationToken != null) {
+ mOperationToken = null;
+ mKeyStore.abort(operationToken);
+ }
+ mOperationHandle = null;
+ mMainDataStreamer = null;
+ mAdditionalEntropyForBegin = null;
+ }
+
+ private void ensureKeystoreOperationInitialized() {
+ if (mMainDataStreamer != null) {
+ return;
+ }
+ if (mKey == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+
+ KeymasterArguments keymasterInputArgs = new KeymasterArguments();
+ keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm);
+ keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mBlockMode);
+ keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mPadding);
+ addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
+
+ KeymasterArguments keymasterOutputArgs = new KeymasterArguments();
+ OperationResult opResult = mKeyStore.begin(
+ mKey.getAlias(),
+ mEncrypting ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT,
+ true, // permit aborting this operation if keystore runs out of resources
+ keymasterInputArgs,
+ mAdditionalEntropyForBegin,
+ keymasterOutputArgs);
+ mAdditionalEntropyForBegin = null;
+ if (opResult == null) {
+ throw new KeyStoreConnectException();
+ } else if (opResult.resultCode != KeyStore.NO_ERROR) {
+ throw KeymasterUtils.getCryptoOperationException(opResult.resultCode);
+ }
+
+ if (opResult.token == null) {
+ throw new CryptoOperationException("Keystore returned null operation token");
+ }
+ mOperationToken = opResult.token;
+ mOperationHandle = opResult.operationHandle;
+ loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs);
+ mFirstOperationInitiated = true;
+ mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer(
+ new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
+ mKeyStore, opResult.token));
+ }
+
+ @Override
+ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+ ensureKeystoreOperationInitialized();
+
+ if (inputLen == 0) {
+ return null;
+ }
+
+ byte[] output;
+ try {
+ output = mMainDataStreamer.update(input, inputOffset, inputLen);
+ } catch (KeymasterException e) {
+ throw KeymasterUtils.getCryptoOperationException(e);
+ }
+
+ if (output.length == 0) {
+ return null;
+ }
+
+ return output;
+ }
+
+ @Override
+ protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset) throws ShortBufferException {
+ ensureKeystoreOperationInitialized();
+
+ byte[] outputCopy = engineUpdate(input, inputOffset, inputLen);
+ if (outputCopy == null) {
+ return 0;
+ }
+ int outputAvailable = output.length - outputOffset;
+ if (outputCopy.length > outputAvailable) {
+ throw new ShortBufferException("Output buffer too short. Produced: "
+ + outputCopy.length + ", available: " + outputAvailable);
+ }
+ System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
+ return outputCopy.length;
+ }
+
+ @Override
+ protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException {
+ ensureKeystoreOperationInitialized();
+
+ byte[] output;
+ try {
+ output = mMainDataStreamer.doFinal(input, inputOffset, inputLen);
+ } catch (KeymasterException e) {
+ switch (e.getErrorCode()) {
+ case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
+ throw new IllegalBlockSizeException();
+ case KeymasterDefs.KM_ERROR_INVALID_ARGUMENT:
+ throw new BadPaddingException();
+ case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
+ throw new AEADBadTagException();
+ default:
+ throw KeymasterUtils.getCryptoOperationException(e);
+ }
+ }
+
+ reset();
+ return output;
+ }
+
+ @Override
+ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ byte[] outputCopy = engineDoFinal(input, inputOffset, inputLen);
+ if (outputCopy == null) {
+ return 0;
+ }
+ int outputAvailable = output.length - outputOffset;
+ if (outputCopy.length > outputAvailable) {
+ throw new ShortBufferException("Output buffer too short. Produced: "
+ + outputCopy.length + ", available: " + outputAvailable);
+ }
+ System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
+ return outputCopy.length;
+ }
+
+ @Override
+ protected int engineGetBlockSize() {
+ return mBlockSizeBytes;
+ }
+
+ @Override
+ protected byte[] engineGetIV() {
+ return (mIv != null) ? mIv.clone() : null;
+ }
+
+ @Override
+ protected int engineGetOutputSize(int inputLen) {
+ return inputLen + 3 * engineGetBlockSize();
+ }
+
+ @Override
+ protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+ // This should never be invoked because all algorithms registered with the AndroidKeyStore
+ // provide explicitly specify block mode.
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void engineSetPadding(String arg0) throws NoSuchPaddingException {
+ // This should never be invoked because all algorithms registered with the AndroidKeyStore
+ // provide explicitly specify padding mode.
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void finalize() throws Throwable {
+ try {
+ IBinder operationToken = mOperationToken;
+ if (operationToken != null) {
+ mKeyStore.abort(operationToken);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public Long getOperationHandle() {
+ return mOperationHandle;
+ }
+
+ // The methods below may need to be overridden by subclasses that use algorithm-specific
+ // parameters.
+
+ /**
+ * Returns algorithm-specific parameters used by this {@code CipherSpi} instance or {@code null}
+ * if no algorithm-specific parameters are used.
+ *
+ * <p>This implementation only handles the IV parameter.
+ */
+ @Override
+ protected AlgorithmParameters engineGetParameters() {
+ if (!mIvUsed) {
+ return null;
+ }
+ if ((mIv != null) && (mIv.length > 0)) {
+ try {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
+ params.init(new IvParameterSpec(mIv));
+ return params;
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("Failed to obtain AES AlgorithmParameters", e);
+ } catch (InvalidParameterSpecException e) {
+ throw new RuntimeException(
+ "Failed to initialize AES AlgorithmParameters with an IV", e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Invoked by {@code engineInit} to initialize algorithm-specific parameters. These parameters
+ * may need to be stored to be reused after {@code doFinal}.
+ *
+ * <p>The default implementation only handles the IV parameters.
+ *
+ * @param params algorithm parameters.
+ *
+ * @throws InvalidAlgorithmParameterException if some/all of the parameters cannot be
+ * automatically configured and thus {@code Cipher.init} needs to be invoked with
+ * explicitly provided parameters.
+ */
+ protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException {
+ if (!mIvUsed) {
+ if (params != null) {
+ throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
+ }
+ return;
+ }
+
+ // IV is used
+ if (params == null) {
+ if (!mEncrypting) {
+ // IV must be provided by the caller
+ throw new InvalidAlgorithmParameterException(
+ "IvParameterSpec must be provided when decrypting");
+ }
+ return;
+ }
+ if (!(params instanceof IvParameterSpec)) {
+ throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported");
+ }
+ mIv = ((IvParameterSpec) params).getIV();
+ if (mIv == null) {
+ throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec");
+ }
+ }
+
+ /**
+ * Invoked by {@code engineInit} to initialize algorithm-specific parameters. These parameters
+ * may need to be stored to be reused after {@code doFinal}.
+ *
+ * <p>The default implementation only handles the IV parameters.
+ *
+ * @param params algorithm parameters.
+ *
+ * @throws InvalidAlgorithmParameterException if some/all of the parameters cannot be
+ * automatically configured and thus {@code Cipher.init} needs to be invoked with
+ * explicitly provided parameters.
+ */
+ protected void initAlgorithmSpecificParameters(AlgorithmParameters params)
+ throws InvalidAlgorithmParameterException {
+ if (!mIvUsed) {
+ if (params != null) {
+ throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
+ }
+ return;
+ }
+
+ // IV is used
+ if (params == null) {
+ if (!mEncrypting) {
+ // IV must be provided by the caller
+ throw new InvalidAlgorithmParameterException("IV required when decrypting"
+ + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
+ }
+ return;
+ }
+
+ IvParameterSpec ivSpec;
+ try {
+ ivSpec = params.getParameterSpec(IvParameterSpec.class);
+ } catch (InvalidParameterSpecException e) {
+ if (!mEncrypting) {
+ // IV must be provided by the caller
+ throw new InvalidAlgorithmParameterException("IV required when decrypting"
+ + ", but not found in parameters: " + params, e);
+ }
+ mIv = null;
+ return;
+ }
+ mIv = ivSpec.getIV();
+ if (mIv == null) {
+ throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters");
+ }
+ }
+
+ /**
+ * Invoked by {@code engineInit} to initialize algorithm-specific parameters. These parameters
+ * may need to be stored to be reused after {@code doFinal}.
+ *
+ * <p>The default implementation only handles the IV parameter.
+ *
+ * @throws InvalidKeyException if some/all of the parameters cannot be automatically configured
+ * and thus {@code Cipher.init} needs to be invoked with explicitly provided parameters.
+ */
+ protected void initAlgorithmSpecificParameters() throws InvalidKeyException {
+ if (!mIvUsed) {
+ return;
+ }
+
+ // IV is used
+ if (!mEncrypting) {
+ throw new InvalidKeyException("IV required when decrypting"
+ + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
+ }
+ }
+
+ /**
+ * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
+ *
+ * <p>The default implementation takes care of the IV.
+ *
+ * @param keymasterArgs keystore/keymaster arguments to be populated with algorithm-specific
+ * parameters.
+ */
+ protected void addAlgorithmSpecificParametersToBegin(KeymasterArguments keymasterArgs) {
+ if (!mFirstOperationInitiated) {
+ // First begin operation -- see if we need to provide additional entropy for IV
+ // generation.
+ if (mIvUsed) {
+ // IV is needed
+ if ((mIv == null) && (mEncrypting)) {
+ // TODO: Switch to keymaster-generated IV code below once keymaster supports
+ // that.
+ // IV is needed but was not provided by the caller -- generate an IV.
+ mIv = new byte[mBlockSizeBytes];
+ SecureRandom rng = (mRng != null) ? mRng : new SecureRandom();
+ rng.nextBytes(mIv);
+// // IV was not provided by the caller and thus will be generated by keymaster.
+// // Mix in some additional entropy from the provided SecureRandom.
+// if (mRng != null) {
+// mAdditionalEntropyForBegin = new byte[mBlockSizeBytes];
+// mRng.nextBytes(mAdditionalEntropyForBegin);
+// }
+ }
+ }
+ }
+
+ if ((mIvUsed) && (mIv != null)) {
+ keymasterArgs.addBlob(KeymasterDefs.KM_TAG_NONCE, mIv);
+ }
+ }
+
+ /**
+ * Invoked by {@code engineInit} to obtain algorithm-specific parameters from the result of the
+ * Keymaster's {@code begin} operation. Some of these parameters may need to be reused after
+ * {@code doFinal} by {@link #addAlgorithmSpecificParametersToBegin(KeymasterArguments)}.
+ *
+ * <p>The default implementation only takes care of the IV.
+ *
+ * @param keymasterArgs keystore/keymaster arguments returned by KeyStore {@code begin}
+ * operation.
+ */
+ protected void loadAlgorithmSpecificParametersFromBeginResult(
+ KeymasterArguments keymasterArgs) {
+ // NOTE: Keymaster doesn't always return an IV, even if it's used.
+ byte[] returnedIv = keymasterArgs.getBlob(KeymasterDefs.KM_TAG_NONCE, null);
+ if ((returnedIv != null) && (returnedIv.length == 0)) {
+ returnedIv = null;
+ }
+
+ if (mIvUsed) {
+ if (mIv == null) {
+ mIv = returnedIv;
+ } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
+ throw new CryptoOperationException("IV in use differs from provided IV");
+ }
+ } else {
+ if (returnedIv != null) {
+ throw new CryptoOperationException(
+ "IV in use despite IV not being used by this transformation");
+ }
+ }
+ }
+}
diff --git a/keystore/java/android/security/KeyStoreConnectException.java b/keystore/java/android/security/KeyStoreConnectException.java
new file mode 100644
index 0000000..8ed6e04
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreConnectException.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates a communications error with keystore service.
+ *
+ * @hide
+ */
+public class KeyStoreConnectException extends CryptoOperationException {
+ public KeyStoreConnectException() {
+ super("Failed to communicate with keystore service");
+ }
+}
diff --git a/keystore/java/android/security/KeyStoreCryptoOperation.java b/keystore/java/android/security/KeyStoreCryptoOperation.java
new file mode 100644
index 0000000..19abd05
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreCryptoOperation.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Cryptographic operation backed by {@link KeyStore}.
+ *
+ * @hide
+ */
+public interface KeyStoreCryptoOperation {
+ /**
+ * Gets the KeyStore operation handle of this crypto operation.
+ *
+ * @return handle or {@code null} if the KeyStore operation is not in progress.
+ */
+ Long getOperationHandle();
+}
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
new file mode 100644
index 0000000..993614b
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.os.IBinder;
+import android.security.keymaster.OperationResult;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
+ * {@code update} and {@code finish} operations.
+ *
+ * <p>The helper abstracts away to issues that need to be solved in most code that uses KeyStore's
+ * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
+ * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
+ * operation may consume less data than provided, in which case the caller has to buffer the
+ * remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
+ * {@link #doFinal(byte[], int, int) doFinal} operations which can be used to conveniently implement
+ * various JCA crypto primitives.
+ *
+ * <p>Bidirectional chunked streaming of data via a KeyStore crypto operation is abstracted away as
+ * a {@link Stream} to avoid having this class deal with operation tokens and occasional additional
+ * parameters to {@code update} and {@code final} operations.
+ *
+ * @hide
+ */
+public class KeyStoreCryptoOperationChunkedStreamer {
+
+ /**
+ * Bidirectional chunked data stream over a KeyStore crypto operation.
+ */
+ public interface Stream {
+ /**
+ * Returns the result of the KeyStore {@code update} operation or null if keystore couldn't
+ * be reached.
+ */
+ OperationResult update(byte[] input);
+
+ /**
+ * Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
+ * be reached.
+ */
+ OperationResult finish();
+ }
+
+ // Binder buffer is about 1MB, but it's shared between all active transactions of the process.
+ // Thus, it's safer to use a much smaller upper bound.
+ private static final int DEFAULT_MAX_CHUNK_SIZE = 64 * 1024;
+ private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+ private final Stream mKeyStoreStream;
+ private final int mMaxChunkSize;
+
+ private byte[] mBuffered = EMPTY_BYTE_ARRAY;
+ private int mBufferedOffset;
+ private int mBufferedLength;
+
+ public KeyStoreCryptoOperationChunkedStreamer(Stream operation) {
+ this(operation, DEFAULT_MAX_CHUNK_SIZE);
+ }
+
+ public KeyStoreCryptoOperationChunkedStreamer(Stream operation, int maxChunkSize) {
+ mKeyStoreStream = operation;
+ mMaxChunkSize = maxChunkSize;
+ }
+
+ public byte[] update(byte[] input, int inputOffset, int inputLength) throws KeymasterException {
+ if (inputLength == 0) {
+ // No input provided
+ return EMPTY_BYTE_ARRAY;
+ }
+
+ ByteArrayOutputStream bufferedOutput = null;
+
+ while (inputLength > 0) {
+ byte[] chunk;
+ int inputBytesInChunk;
+ if ((mBufferedLength + inputLength) > mMaxChunkSize) {
+ // Too much input for one chunk -- extract one max-sized chunk and feed it into the
+ // update operation.
+ inputBytesInChunk = mMaxChunkSize - mBufferedLength;
+ chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+ input, inputOffset, inputBytesInChunk);
+ } else {
+ // All of available input fits into one chunk.
+ if ((mBufferedLength == 0) && (inputOffset == 0)
+ && (inputLength == input.length)) {
+ // Nothing buffered and all of input array needs to be fed into the update
+ // operation.
+ chunk = input;
+ inputBytesInChunk = input.length;
+ } else {
+ // Need to combine buffered data with input data into one array.
+ inputBytesInChunk = inputLength;
+ chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+ input, inputOffset, inputBytesInChunk);
+ }
+ }
+ // Update input array references to reflect that some of its bytes are now in mBuffered.
+ inputOffset += inputBytesInChunk;
+ inputLength -= inputBytesInChunk;
+
+ OperationResult opResult = mKeyStoreStream.update(chunk);
+ if (opResult == null) {
+ throw new KeyStoreConnectException();
+ } else if (opResult.resultCode != KeyStore.NO_ERROR) {
+ throw KeymasterUtils.getKeymasterException(opResult.resultCode);
+ }
+
+ if (opResult.inputConsumed == chunk.length) {
+ // The whole chunk was consumed
+ mBuffered = EMPTY_BYTE_ARRAY;
+ mBufferedOffset = 0;
+ mBufferedLength = 0;
+ } else if (opResult.inputConsumed == 0) {
+ // Nothing was consumed. More input needed.
+ if (inputLength > 0) {
+ // More input is available, but it wasn't included into the previous chunk
+ // because the chunk reached its maximum permitted size.
+ // Shouldn't have happened.
+ throw new CryptoOperationException("Nothing consumed from max-sized chunk: "
+ + chunk.length + " bytes");
+ }
+ mBuffered = chunk;
+ mBufferedOffset = 0;
+ mBufferedLength = chunk.length;
+ } else if (opResult.inputConsumed < chunk.length) {
+ // The chunk was consumed only partially -- buffer the rest of the chunk
+ mBuffered = chunk;
+ mBufferedOffset = opResult.inputConsumed;
+ mBufferedLength = chunk.length - opResult.inputConsumed;
+ } else {
+ throw new CryptoOperationException("Consumed more than provided: "
+ + opResult.inputConsumed + ", provided: " + chunk.length);
+ }
+
+ if ((opResult.output != null) && (opResult.output.length > 0)) {
+ if (inputLength > 0) {
+ // More output might be produced in this loop -- buffer the current output
+ if (bufferedOutput == null) {
+ bufferedOutput = new ByteArrayOutputStream();
+ try {
+ bufferedOutput.write(opResult.output);
+ } catch (IOException e) {
+ throw new CryptoOperationException("Failed to buffer output", e);
+ }
+ }
+ } else {
+ // No more output will be produced in this loop
+ if (bufferedOutput == null) {
+ // No previously buffered output
+ return opResult.output;
+ } else {
+ // There was some previously buffered output
+ try {
+ bufferedOutput.write(opResult.output);
+ } catch (IOException e) {
+ throw new CryptoOperationException("Failed to buffer output", e);
+ }
+ return bufferedOutput.toByteArray();
+ }
+ }
+ }
+ }
+
+ if (bufferedOutput == null) {
+ // No output produced
+ return EMPTY_BYTE_ARRAY;
+ } else {
+ return bufferedOutput.toByteArray();
+ }
+ }
+
+ public byte[] doFinal(byte[] input, int inputOffset, int inputLength)
+ throws KeymasterException {
+ if (inputLength == 0) {
+ // No input provided -- simplify the rest of the code
+ input = EMPTY_BYTE_ARRAY;
+ inputOffset = 0;
+ }
+
+ // Flush all buffered input and provided input into keystore/keymaster.
+ byte[] output = update(input, inputOffset, inputLength);
+ output = concat(output, flush());
+
+ OperationResult opResult = mKeyStoreStream.finish();
+ if (opResult == null) {
+ throw new KeyStoreConnectException();
+ } else if (opResult.resultCode != KeyStore.NO_ERROR) {
+ throw KeymasterUtils.getKeymasterException(opResult.resultCode);
+ }
+
+ return concat(output, opResult.output);
+ }
+
+ /**
+ * Passes all of buffered input into the the KeyStore operation (via the {@code update}
+ * operation) and returns output.
+ */
+ public byte[] flush() throws KeymasterException {
+ if (mBufferedLength <= 0) {
+ return EMPTY_BYTE_ARRAY;
+ }
+
+ byte[] chunk = subarray(mBuffered, mBufferedOffset, mBufferedLength);
+ mBuffered = EMPTY_BYTE_ARRAY;
+ mBufferedLength = 0;
+ mBufferedOffset = 0;
+
+ OperationResult opResult = mKeyStoreStream.update(chunk);
+ if (opResult == null) {
+ throw new KeyStoreConnectException();
+ } else if (opResult.resultCode != KeyStore.NO_ERROR) {
+ throw KeymasterUtils.getKeymasterException(opResult.resultCode);
+ }
+
+ if (opResult.inputConsumed < chunk.length) {
+ throw new CryptoOperationException("Keystore failed to consume all input. Provided: "
+ + chunk.length + ", consumed: " + opResult.inputConsumed);
+ } else if (opResult.inputConsumed > chunk.length) {
+ throw new CryptoOperationException("Keystore consumed more input than provided"
+ + " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed);
+ }
+
+ return (opResult.output != null) ? opResult.output : EMPTY_BYTE_ARRAY;
+ }
+
+ private static byte[] concat(byte[] arr1, byte[] arr2) {
+ if ((arr1 == null) || (arr1.length == 0)) {
+ return arr2;
+ } else if ((arr2 == null) || (arr2.length == 0)) {
+ return arr1;
+ } else {
+ byte[] result = new byte[arr1.length + arr2.length];
+ System.arraycopy(arr1, 0, result, 0, arr1.length);
+ System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
+ return result;
+ }
+ }
+
+ private static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
+ int len2) {
+ if (len1 == 0) {
+ return subarray(arr2, offset2, len2);
+ } else if (len2 == 0) {
+ return subarray(arr1, offset1, len1);
+ } else {
+ byte[] result = new byte[len1 + len2];
+ System.arraycopy(arr1, offset1, result, 0, len1);
+ System.arraycopy(arr2, offset2, result, len1, len2);
+ return result;
+ }
+ }
+
+ private static byte[] subarray(byte[] arr, int offset, int len) {
+ if (len == 0) {
+ return EMPTY_BYTE_ARRAY;
+ }
+ if ((offset == 0) && (len == arr.length)) {
+ return arr;
+ }
+ byte[] result = new byte[len];
+ System.arraycopy(arr, offset, result, 0, len);
+ return result;
+ }
+
+ /**
+ * Main data stream via a KeyStore streaming operation.
+ *
+ * <p>For example, for an encryption operation, this is the stream through which plaintext is
+ * provided and ciphertext is obtained.
+ */
+ public static class MainDataStream implements Stream {
+
+ private final KeyStore mKeyStore;
+ private final IBinder mOperationToken;
+
+ public MainDataStream(KeyStore keyStore, IBinder operationToken) {
+ mKeyStore = keyStore;
+ mOperationToken = operationToken;
+ }
+
+ @Override
+ public OperationResult update(byte[] input) {
+ return mKeyStore.update(mOperationToken, null, input);
+ }
+
+ @Override
+ public OperationResult finish() {
+ return mKeyStore.finish(mOperationToken, null, null);
+ }
+ }
+}
diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java
new file mode 100644
index 0000000..1297cc2
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreHmacSpi.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.os.IBinder;
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterDefs;
+import android.security.keymaster.OperationResult;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.MacSpi;
+
+/**
+ * {@link MacSpi} which provides HMAC implementations backed by Android KeyStore.
+ *
+ * @hide
+ */
+public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOperation {
+
+ public static class HmacSHA256 extends KeyStoreHmacSpi {
+ public HmacSHA256() {
+ super(KeyStoreKeyConstraints.Digest.SHA256, 256 / 8);
+ }
+ }
+
+ private final KeyStore mKeyStore = KeyStore.getInstance();
+ private final @KeyStoreKeyConstraints.DigestEnum int mDigest;
+ private final int mMacSizeBytes;
+
+ private String mKeyAliasInKeyStore;
+
+ // The fields below are reset by the engineReset operation.
+ private KeyStoreCryptoOperationChunkedStreamer mChunkedStreamer;
+ private IBinder mOperationToken;
+ private Long mOperationHandle;
+
+ protected KeyStoreHmacSpi(@KeyStoreKeyConstraints.DigestEnum int digest, int macSizeBytes) {
+ mDigest = digest;
+ mMacSizeBytes = macSizeBytes;
+ }
+
+ @Override
+ protected int engineGetMacLength() {
+ return mMacSizeBytes;
+ }
+
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ if (key == null) {
+ throw new InvalidKeyException("key == null");
+ } else if (!(key instanceof KeyStoreSecretKey)) {
+ throw new InvalidKeyException(
+ "Only Android KeyStore secret keys supported. Key: " + key);
+ }
+
+ if (params != null) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported algorithm parameters: " + params);
+ }
+
+ mKeyAliasInKeyStore = ((KeyStoreSecretKey) key).getAlias();
+ engineReset();
+ }
+
+ @Override
+ protected void engineReset() {
+ IBinder operationToken = mOperationToken;
+ if (operationToken != null) {
+ mOperationToken = null;
+ mKeyStore.abort(operationToken);
+ }
+ mOperationHandle = null;
+ mChunkedStreamer = null;
+
+ KeymasterArguments keymasterArgs = new KeymasterArguments();
+ keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mDigest);
+
+ OperationResult opResult = mKeyStore.begin(mKeyAliasInKeyStore,
+ KeymasterDefs.KM_PURPOSE_SIGN,
+ true,
+ keymasterArgs,
+ null,
+ new KeymasterArguments());
+ if (opResult == null) {
+ throw new KeyStoreConnectException();
+ } else if (opResult.resultCode != KeyStore.NO_ERROR) {
+ throw KeymasterUtils.getCryptoOperationException(opResult.resultCode);
+ }
+ mOperationToken = opResult.token;
+ if (mOperationToken == null) {
+ throw new CryptoOperationException("Keystore returned null operation token");
+ }
+ mOperationHandle = opResult.operationHandle;
+ mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
+ new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
+ mKeyStore, mOperationToken));
+ }
+
+ @Override
+ protected void engineUpdate(byte input) {
+ engineUpdate(new byte[] {input}, 0, 1);
+ }
+
+ @Override
+ protected void engineUpdate(byte[] input, int offset, int len) {
+ if (mChunkedStreamer == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+
+ byte[] output;
+ try {
+ output = mChunkedStreamer.update(input, offset, len);
+ } catch (KeymasterException e) {
+ throw KeymasterUtils.getCryptoOperationException(e);
+ }
+ if ((output != null) && (output.length != 0)) {
+ throw new CryptoOperationException("Update operation unexpectedly produced output");
+ }
+ }
+
+ @Override
+ protected byte[] engineDoFinal() {
+ if (mChunkedStreamer == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+
+ byte[] result;
+ try {
+ result = mChunkedStreamer.doFinal(null, 0, 0);
+ } catch (KeymasterException e) {
+ throw KeymasterUtils.getCryptoOperationException(e);
+ }
+
+ engineReset();
+ return result;
+ }
+
+ @Override
+ public void finalize() throws Throwable {
+ try {
+ IBinder operationToken = mOperationToken;
+ if (operationToken != null) {
+ mKeyStore.abort(operationToken);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public Long getOperationHandle() {
+ return mOperationHandle;
+ }
+}
diff --git a/keystore/java/android/security/KeyStoreKeyCharacteristics.java b/keystore/java/android/security/KeyStoreKeyCharacteristics.java
new file mode 100644
index 0000000..543b5d8
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreKeyCharacteristics.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.IntDef;
+import android.security.keymaster.KeymasterDefs;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Characteristics of {@code AndroidKeyStore} keys.
+ *
+ * @hide
+ */
+public abstract class KeyStoreKeyCharacteristics {
+ private KeyStoreKeyCharacteristics() {}
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({Origin.GENERATED_INSIDE_TEE, Origin.GENERATED_OUTSIDE_OF_TEE, Origin.IMPORTED})
+ public @interface OriginEnum {}
+
+ /**
+ * Origin of the key.
+ */
+ public static abstract class Origin {
+ private Origin() {}
+
+ /** Key was generated inside a TEE. */
+ public static final int GENERATED_INSIDE_TEE = 1;
+
+ /** Key was generated outside of a TEE. */
+ public static final int GENERATED_OUTSIDE_OF_TEE = 2;
+
+ /** Key was imported. */
+ public static final int IMPORTED = 0;
+
+ /**
+ * @hide
+ */
+ public static @OriginEnum int fromKeymaster(int origin) {
+ switch (origin) {
+ case KeymasterDefs.KM_ORIGIN_HARDWARE:
+ return GENERATED_INSIDE_TEE;
+ case KeymasterDefs.KM_ORIGIN_SOFTWARE:
+ return GENERATED_OUTSIDE_OF_TEE;
+ case KeymasterDefs.KM_ORIGIN_IMPORTED:
+ return IMPORTED;
+ default:
+ throw new IllegalArgumentException("Unknown origin: " + origin);
+ }
+ }
+ }
+}
diff --git a/keystore/java/android/security/KeyStoreKeyConstraints.java b/keystore/java/android/security/KeyStoreKeyConstraints.java
index 47bb1cc..75034d1 100644
--- a/keystore/java/android/security/KeyStoreKeyConstraints.java
+++ b/keystore/java/android/security/KeyStoreKeyConstraints.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.security;
import android.annotation.IntDef;
@@ -7,7 +23,10 @@
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.Locale;
+import java.util.Set;
/**
* Constraints for {@code AndroidKeyStore} keys.
@@ -222,16 +241,6 @@
throw new IllegalArgumentException("Unsupported key algorithm: " + algorithm);
}
}
-
- /**
- * @hide
- */
- public static String toJCAKeyPairAlgorithm(@AlgorithmEnum int algorithm) {
- switch (algorithm) {
- default:
- throw new IllegalArgumentException("Unsupported key alorithm: " + algorithm);
- }
- }
}
@Retention(RetentionPolicy.SOURCE)
@@ -306,6 +315,20 @@
throw new IllegalArgumentException("Unknown padding: " + padding);
}
}
+
+ /**
+ * @hide
+ */
+ public static @PaddingEnum int fromJCAPadding(String padding) {
+ String paddingLower = padding.toLowerCase(Locale.US);
+ if ("nopadding".equals(paddingLower)) {
+ return NONE;
+ } else if ("pkcs7padding".equals(paddingLower)) {
+ return PKCS7;
+ } else {
+ throw new IllegalArgumentException("Unknown padding: " + padding);
+ }
+ }
}
@Retention(RetentionPolicy.SOURCE)
@@ -401,10 +424,24 @@
throw new IllegalArgumentException("Unknown digest: " + digest);
}
}
+
+ /**
+ * @hide
+ */
+ public static Integer getOutputSizeBytes(@DigestEnum int digest) {
+ switch (digest) {
+ case NONE:
+ return null;
+ case SHA256:
+ return 256 / 8;
+ default:
+ throw new IllegalArgumentException("Unknown digest: " + digest);
+ }
+ }
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef({BlockMode.ECB})
+ @IntDef({BlockMode.ECB, BlockMode.CBC, BlockMode.CTR})
public @interface BlockModeEnum {}
/**
@@ -413,11 +450,15 @@
public static abstract class BlockMode {
private BlockMode() {}
- /**
- * Electronic Codebook (ECB) block mode.
- */
+ /** Electronic Codebook (ECB) block mode. */
public static final int ECB = 0;
+ /** Cipher Block Chaining (CBC) block mode. */
+ public static final int CBC = 1;
+
+ /** Counter (CTR) block mode. */
+ public static final int CTR = 2;
+
/**
* @hide
*/
@@ -425,6 +466,10 @@
switch (mode) {
case ECB:
return KeymasterDefs.KM_MODE_ECB;
+ case CBC:
+ return KeymasterDefs.KM_MODE_CBC;
+ case CTR:
+ return KeymasterDefs.KM_MODE_CTR;
default:
throw new IllegalArgumentException("Unknown block mode: " + mode);
}
@@ -437,6 +482,10 @@
switch (mode) {
case KeymasterDefs.KM_MODE_ECB:
return ECB;
+ case KeymasterDefs.KM_MODE_CBC:
+ return CBC;
+ case KeymasterDefs.KM_MODE_CTR:
+ return CTR;
default:
throw new IllegalArgumentException("Unknown block mode: " + mode);
}
@@ -449,9 +498,121 @@
switch (mode) {
case ECB:
return "ECB";
+ case CBC:
+ return "CBC";
+ case CTR:
+ return "CTR";
default:
throw new IllegalArgumentException("Unknown block mode: " + mode);
}
}
+
+ /**
+ * @hide
+ */
+ public static @BlockModeEnum int fromJCAMode(String mode) {
+ String modeLower = mode.toLowerCase(Locale.US);
+ if ("ecb".equals(modeLower)) {
+ return ECB;
+ } else if ("cbc".equals(modeLower)) {
+ return CBC;
+ } else if ("ctr".equals(modeLower)) {
+ return CTR;
+ } else {
+ throw new IllegalArgumentException("Unknown block mode: " + mode);
+ }
+ }
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({UserAuthenticator.LOCK_SCREEN})
+ public @interface UserAuthenticatorEnum {}
+
+ /**
+ * User authenticators which can be used to restrict/protect access to keys.
+ */
+ public static abstract class UserAuthenticator {
+ private UserAuthenticator() {}
+
+ /** Lock screen. */
+ public static final int LOCK_SCREEN = 1;
+
+ /** Fingerprint reader/sensor. */
+ public static final int FINGERPRINT_READER = 1 << 1;
+
+ /**
+ * @hide
+ */
+ public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
+ switch (userAuthenticator) {
+ case LOCK_SCREEN:
+ return LOCK_SCREEN;
+ case FINGERPRINT_READER:
+ return FINGERPRINT_READER;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown user authenticator: " + userAuthenticator);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
+ switch (userAuthenticator) {
+ case LOCK_SCREEN:
+ return LOCK_SCREEN;
+ case FINGERPRINT_READER:
+ return FINGERPRINT_READER;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown user authenticator: " + userAuthenticator);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static int allToKeymaster(Set<Integer> userAuthenticators) {
+ int result = 0;
+ for (@UserAuthenticatorEnum int userAuthenticator : userAuthenticators) {
+ result |= toKeymaster(userAuthenticator);
+ }
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ public static Set<Integer> allFromKeymaster(int userAuthenticators) {
+ int userAuthenticator = 1;
+ Set<Integer> result = null;
+ while (userAuthenticators != 0) {
+ if ((userAuthenticators & 1) != 0) {
+ if (result == null) {
+ result = new HashSet<Integer>();
+ }
+ result.add(fromKeymaster(userAuthenticator));
+ }
+ userAuthenticators >>>= 1;
+ userAuthenticator <<= 1;
+ }
+ return (result != null) ? result : Collections.<Integer>emptySet();
+ }
+
+ /**
+ * @hide
+ */
+ public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
+ switch (userAuthenticator) {
+ case LOCK_SCREEN:
+ return "LOCK_SCREEN";
+ case FINGERPRINT_READER:
+ return "FINGERPRINT_READER";
+ default:
+ throw new IllegalArgumentException(
+ "Unknown user authenticator: " + userAuthenticator);
+ }
+ }
}
}
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index 86950dd..8b0a3e9 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.security;
import android.security.keymaster.KeyCharacteristics;
@@ -7,6 +23,7 @@
import java.security.InvalidAlgorithmParameterException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
+import java.util.Date;
import javax.crypto.KeyGeneratorSpi;
import javax.crypto.SecretKey;
@@ -28,13 +45,14 @@
public HmacSHA256() {
super(KeyStoreKeyConstraints.Algorithm.HMAC,
KeyStoreKeyConstraints.Digest.SHA256,
- 256);
+ KeyStoreKeyConstraints.Digest.getOutputSizeBytes(
+ KeyStoreKeyConstraints.Digest.SHA256) * 8);
}
}
private final KeyStore mKeyStore = KeyStore.getInstance();
private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
- private final @KeyStoreKeyConstraints.AlgorithmEnum Integer mDigest;
+ private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
private final int mDefaultKeySizeBits;
private KeyGeneratorSpec mSpec;
@@ -75,6 +93,19 @@
if (mDigest != null) {
args.addInt(KeymasterDefs.KM_TAG_DIGEST,
KeyStoreKeyConstraints.Digest.toKeymaster(mDigest));
+ Integer digestOutputSizeBytes =
+ KeyStoreKeyConstraints.Digest.getOutputSizeBytes(mDigest);
+ if (digestOutputSizeBytes != null) {
+ // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
+ // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
+ args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
+ }
+ }
+ if (mAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
+ if (mDigest == null) {
+ throw new IllegalStateException("Digest algorithm must be specified for key"
+ + " algorithm " + KeyStoreKeyConstraints.Algorithm.toString(mAlgorithm));
+ }
}
int keySizeBits = (spec.getKeySize() != null) ? spec.getKeySize() : mDefaultKeySizeBits;
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits);
@@ -106,26 +137,27 @@
if (spec.getUserAuthenticators().isEmpty()) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
} else {
- // TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized
-// for (int userAuthenticatorId : spec.getUserAuthenticators()) {
-// args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId);
-// }
+ args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
+ KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+ spec.getUserAuthenticators()));
+ }
+ if (spec.isInvalidatedOnNewFingerprintEnrolled()) {
+ // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
+ // that.
}
if (spec.getUserAuthenticationValidityDurationSeconds() != null) {
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
spec.getUserAuthenticationValidityDurationSeconds());
}
- if (spec.getKeyValidityStart() != null) {
- args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
- }
- if (spec.getKeyValidityForOriginationEnd() != null) {
- args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- spec.getKeyValidityForOriginationEnd());
- }
- if (spec.getKeyValidityForConsumptionEnd() != null) {
- args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- spec.getKeyValidityForConsumptionEnd());
- }
+ args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
+ (spec.getKeyValidityStart() != null)
+ ? spec.getKeyValidityStart() : new Date(0));
+ args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+ (spec.getKeyValidityForOriginationEnd() != null)
+ ? spec.getKeyValidityForOriginationEnd() : new Date(Long.MAX_VALUE));
+ args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+ (spec.getKeyValidityForConsumptionEnd() != null)
+ ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
|| ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) {
@@ -145,8 +177,7 @@
int errorCode = mKeyStore.generateKey(
keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics());
if (errorCode != KeyStore.NO_ERROR) {
- throw new CryptoOperationException("Failed to generate key",
- KeymasterUtils.getExceptionForKeymasterError(errorCode));
+ throw KeymasterUtils.getCryptoOperationException(errorCode);
}
String keyAlgorithmJCA =
KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java
new file mode 100644
index 0000000..e5e5acc
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreKeySpec.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import java.security.spec.KeySpec;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android
+ * KeyStore</a>.
+ *
+ * @hide
+ */
+public class KeyStoreKeySpec implements KeySpec {
+ private final String mKeystoreAlias;
+ private final int mKeySize;
+ private final @KeyStoreKeyCharacteristics.OriginEnum int mOrigin;
+ private final Date mKeyValidityStart;
+ private final Date mKeyValidityForOriginationEnd;
+ private final Date mKeyValidityForConsumptionEnd;
+ private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+ private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
+ private final @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
+ private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
+ private final @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
+ private final Integer mMinSecondsBetweenOperations;
+ private final Integer mMaxUsesPerBoot;
+ private final Set<Integer> mUserAuthenticators;
+ private final Set<Integer> mTeeBackedUserAuthenticators;
+ private final Integer mUserAuthenticationValidityDurationSeconds;
+ private final boolean mInvalidatedOnNewFingerprintEnrolled;
+
+
+ /**
+ * @hide
+ */
+ KeyStoreKeySpec(String keystoreKeyAlias,
+ @KeyStoreKeyCharacteristics.OriginEnum int origin,
+ int keySize, Date keyValidityStart, Date keyValidityForOriginationEnd,
+ Date keyValidityForConsumptionEnd,
+ @KeyStoreKeyConstraints.PurposeEnum int purposes,
+ @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
+ @KeyStoreKeyConstraints.PaddingEnum Integer padding,
+ @KeyStoreKeyConstraints.DigestEnum Integer digest,
+ @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode,
+ Integer minSecondsBetweenOperations,
+ Integer maxUsesPerBoot,
+ Set<Integer> userAuthenticators,
+ Set<Integer> teeBackedUserAuthenticators,
+ Integer userAuthenticationValidityDurationSeconds,
+ boolean invalidatedOnNewFingerprintEnrolled) {
+ mKeystoreAlias = keystoreKeyAlias;
+ mOrigin = origin;
+ mKeySize = keySize;
+ mKeyValidityStart = keyValidityStart;
+ mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
+ mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
+ mPurposes = purposes;
+ mAlgorithm = algorithm;
+ mPadding = padding;
+ mDigest = digest;
+ mBlockMode = blockMode;
+ mMinSecondsBetweenOperations = minSecondsBetweenOperations;
+ mMaxUsesPerBoot = maxUsesPerBoot;
+ mUserAuthenticators = (userAuthenticators != null)
+ ? new HashSet<Integer>(userAuthenticators)
+ : Collections.<Integer>emptySet();
+ mTeeBackedUserAuthenticators = (teeBackedUserAuthenticators != null)
+ ? new HashSet<Integer>(teeBackedUserAuthenticators)
+ : Collections.<Integer>emptySet();
+ mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
+ }
+
+ /**
+ * Gets the entry alias under which the key is stored in the {@code AndroidKeyStore}.
+ */
+ public String getKeystoreAlias() {
+ return mKeystoreAlias;
+ }
+
+ /**
+ * Gets the origin of the key.
+ */
+ public @KeyStoreKeyCharacteristics.OriginEnum int getOrigin() {
+ return mOrigin;
+ }
+
+ /**
+ * Gets the key's size in bits.
+ */
+ public int getKeySize() {
+ return mKeySize;
+ }
+
+ /**
+ * Gets the time instant before which the key is not yet valid.
+ *
+ * @return instant or {@code null} if not restricted.
+ */
+ public Date getKeyValidityStart() {
+ return mKeyValidityStart;
+ }
+
+ /**
+ * Gets the time instant after which the key is no long valid for decryption and verification.
+ *
+ * @return instant or {@code null} if not restricted.
+ */
+ public Date getKeyValidityForConsumptionEnd() {
+ return mKeyValidityForConsumptionEnd;
+ }
+
+ /**
+ * Gets the time instant after which the key is no long valid for encryption and signing.
+ *
+ * @return instant or {@code null} if not restricted.
+ */
+ public Date getKeyValidityForOriginationEnd() {
+ return mKeyValidityForOriginationEnd;
+ }
+
+ /**
+ * Gets the set of purposes for which the key can be used.
+ */
+ public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+ return mPurposes;
+ }
+
+ /**
+ * Gets the algorithm of the key.
+ */
+ public @KeyStoreKeyConstraints.AlgorithmEnum int getAlgorithm() {
+ return mAlgorithm;
+ }
+
+ /**
+ * Gets the only block mode with which the key can be used.
+ *
+ * @return block mode or {@code null} if the block mode is not restricted.
+ */
+ public @KeyStoreKeyConstraints.BlockModeEnum Integer getBlockMode() {
+ return mBlockMode;
+ }
+
+ /**
+ * Gets the only padding mode with which the key can be used.
+ *
+ * @return padding mode or {@code null} if the padding mode is not restricted.
+ */
+ public @KeyStoreKeyConstraints.PaddingEnum Integer getPadding() {
+ return mPadding;
+ }
+
+ /**
+ * Gets the only digest algorithm with which the key can be used.
+ *
+ * @return digest algorithm or {@code null} if the digest algorithm is not restricted.
+ */
+ public @KeyStoreKeyConstraints.DigestEnum Integer getDigest() {
+ return mDigest;
+ }
+
+ /**
+ * Gets the minimum number of seconds that must expire since the most recent use of the key
+ * before it can be used again.
+ *
+ * @return number of seconds or {@code null} if there is no restriction on how frequently a key
+ * can be used.
+ */
+ public Integer getMinSecondsBetweenOperations() {
+ return mMinSecondsBetweenOperations;
+ }
+
+ /**
+ * Gets the number of times the key can be used without rebooting the device.
+ *
+ * @return maximum number of times or {@code null} if there is no restriction.
+ */
+ public Integer getMaxUsesPerBoot() {
+ return mMaxUsesPerBoot;
+ }
+
+ /**
+ * Gets the user authenticators which protect access to the key. The key can only be used iff
+ * the user has authenticated to at least one of these user authenticators.
+ *
+ * @return user authenticators or empty set if the key can be used without user authentication.
+ */
+ public Set<Integer> getUserAuthenticators() {
+ return new HashSet<Integer>(mUserAuthenticators);
+ }
+
+ /**
+ * Gets the TEE-backed user authenticators which protect access to the key. This is a subset of
+ * the user authentications returned by {@link #getUserAuthenticators()}.
+ */
+ public Set<Integer> getTeeBackedUserAuthenticators() {
+ return new HashSet<Integer>(mTeeBackedUserAuthenticators);
+ }
+
+ /**
+ * Gets the duration of time (seconds) for which the key can be used after the user
+ * successfully authenticates to one of the associated user authenticators.
+ *
+ * @return duration in seconds or {@code null} if not restricted. {@code 0} means authentication
+ * is required for every use of the key.
+ */
+ public Integer getUserAuthenticationValidityDurationSeconds() {
+ return mUserAuthenticationValidityDurationSeconds;
+ }
+
+ /**
+ * Returns {@code true} if this key will be permanently invalidated once a new fingerprint is
+ * enrolled. This constraint only has effect if fingerprint reader is one of the user
+ * authenticators protecting access to this key.
+ *
+ * @see #getUserAuthenticators()
+ */
+ public boolean isInvalidatedOnNewFingerprintEnrolled() {
+ return mInvalidatedOnNewFingerprintEnrolled;
+ }
+}
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index 2428c2a..b1b638f 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -59,6 +59,7 @@
private final Integer mMaxUsesPerBoot;
private final Set<Integer> mUserAuthenticators;
private final Integer mUserAuthenticationValidityDurationSeconds;
+ private final boolean mInvalidatedOnNewFingerprintEnrolled;
private KeyStoreParameter(int flags, Date keyValidityStart,
Date keyValidityForOriginationEnd, Date keyValidityForConsumptionEnd,
@@ -70,7 +71,8 @@
Integer minSecondsBetweenOperations,
Integer maxUsesPerBoot,
Set<Integer> userAuthenticators,
- Integer userAuthenticationValidityDurationSeconds) {
+ Integer userAuthenticationValidityDurationSeconds,
+ boolean invalidatedOnNewFingerprintEnrolled) {
if ((userAuthenticationValidityDurationSeconds != null)
&& (userAuthenticationValidityDurationSeconds < 0)) {
throw new IllegalArgumentException(
@@ -92,6 +94,7 @@
? new HashSet<Integer>(userAuthenticators)
: Collections.<Integer>emptySet();
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
}
/**
@@ -245,6 +248,19 @@
}
/**
+ * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+ * enrolled. This constraint only has effect if fingerprint reader is one of the user
+ * authenticators protecting access to this key.
+ *
+ * @see #getUserAuthenticators()
+ *
+ * @hide
+ */
+ public boolean isInvalidatedOnNewFingerprintEnrolled() {
+ return mInvalidatedOnNewFingerprintEnrolled;
+ }
+
+ /**
* Builder class for {@link KeyStoreParameter} objects.
* <p>
* This will build protection parameters for use with the
@@ -275,6 +291,7 @@
private Integer mMaxUsesPerBoot;
private Set<Integer> mUserAuthenticators;
private Integer mUserAuthenticationValidityDurationSeconds;
+ private boolean mInvalidatedOnNewFingerprintEnrolled;
/**
* Creates a new instance of the {@code Builder} with the given
@@ -496,6 +513,22 @@
}
/**
+ * Sets whether this key must be invalidated (permanently) whenever a new fingerprint is
+ * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+ * protecting access to the key.
+ *
+ * <p>By default, enrolling a new fingerprint does not invalidate the key.
+ *
+ * @see #setUserAuthenticators(Set)
+ *
+ * @hide
+ */
+ public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+ mInvalidatedOnNewFingerprintEnrolled = invalidated;
+ return this;
+ }
+
+ /**
* Builds the instance of the {@code KeyStoreParameter}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -506,7 +539,8 @@
mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd, mPurposes,
mAlgorithm, mPadding, mDigest, mBlockMode, mMinSecondsBetweenOperations,
mMaxUsesPerBoot, mUserAuthenticators,
- mUserAuthenticationValidityDurationSeconds);
+ mUserAuthenticationValidityDurationSeconds,
+ mInvalidatedOnNewFingerprintEnrolled);
}
}
}
diff --git a/keystore/java/android/security/KeyStoreSecretKey.java b/keystore/java/android/security/KeyStoreSecretKey.java
index 9410127..7f0e3d3 100644
--- a/keystore/java/android/security/KeyStoreSecretKey.java
+++ b/keystore/java/android/security/KeyStoreSecretKey.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.security;
import javax.crypto.SecretKey;
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
new file mode 100644
index 0000000..c205d9d
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterDefs;
+
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Date;
+import java.util.Set;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * {@link SecretKeyFactorySpi} backed by Android KeyStore.
+ *
+ * @hide
+ */
+public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
+
+ private final KeyStore mKeyStore = KeyStore.getInstance();
+
+ @Override
+ protected KeySpec engineGetKeySpec(SecretKey key,
+ @SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException {
+ if (keySpecClass == null) {
+ throw new InvalidKeySpecException("keySpecClass == null");
+ }
+ if (!(key instanceof KeyStoreSecretKey)) {
+ throw new InvalidKeySpecException("Only Android KeyStore secret keys supported: " +
+ ((key != null) ? key.getClass().getName() : "null"));
+ }
+ if (SecretKeySpec.class.isAssignableFrom(keySpecClass)) {
+ throw new InvalidKeySpecException(
+ "Key material export of Android KeyStore keys is not supported");
+ }
+ if (!KeyStoreKeySpec.class.equals(keySpecClass)) {
+ throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
+ }
+ String keyAliasInKeystore = ((KeyStoreSecretKey) key).getAlias();
+ String entryAlias;
+ if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)) {
+ entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
+ } else {
+ throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
+ }
+
+ KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+ int errorCode =
+ mKeyStore.getKeyCharacteristics(keyAliasInKeystore, null, null, keyCharacteristics);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw new InvalidKeySpecException("Failed to obtain information about key."
+ + " Keystore error: " + errorCode);
+ }
+
+ @KeyStoreKeyCharacteristics.OriginEnum Integer origin;
+ int keySize;
+ @KeyStoreKeyConstraints.PurposeEnum int purposes;
+ @KeyStoreKeyConstraints.AlgorithmEnum int algorithm;
+ @KeyStoreKeyConstraints.PaddingEnum Integer padding;
+ @KeyStoreKeyConstraints.DigestEnum Integer digest;
+ @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode;
+ try {
+ origin = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ORIGIN);
+ if (origin == null) {
+ throw new InvalidKeySpecException("Key origin not available");
+ }
+ origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(origin);
+ Integer keySizeInteger =
+ KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_KEY_SIZE);
+ if (keySizeInteger == null) {
+ throw new InvalidKeySpecException("Key size not available");
+ }
+ keySize = keySizeInteger;
+ purposes = KeyStoreKeyConstraints.Purpose.allFromKeymaster(
+ KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PURPOSE));
+ Integer alg = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ALGORITHM);
+ if (alg == null) {
+ throw new InvalidKeySpecException("Key algorithm not available");
+ }
+ algorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(alg);
+ padding = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_PADDING);
+ if (padding != null) {
+ padding = KeyStoreKeyConstraints.Padding.fromKeymaster(padding);
+ }
+ digest = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_DIGEST);
+ if (digest != null) {
+ digest = KeyStoreKeyConstraints.Digest.fromKeymaster(digest);
+ }
+ blockMode = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_BLOCK_MODE);
+ if (blockMode != null) {
+ blockMode = KeyStoreKeyConstraints.BlockMode.fromKeymaster(blockMode);
+ }
+ } catch (IllegalArgumentException e) {
+ throw new InvalidKeySpecException("Unsupported key characteristic", e);
+ }
+
+ Date keyValidityStart =
+ KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
+ if ((keyValidityStart != null) && (keyValidityStart.getTime() <= 0)) {
+ keyValidityStart = null;
+ }
+ Date keyValidityForOriginationEnd = KeymasterUtils.getDate(keyCharacteristics,
+ KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
+ if ((keyValidityForOriginationEnd != null)
+ && (keyValidityForOriginationEnd.getTime() == Long.MAX_VALUE)) {
+ keyValidityForOriginationEnd = null;
+ }
+ Date keyValidityForConsumptionEnd = KeymasterUtils.getDate(keyCharacteristics,
+ KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
+ if ((keyValidityForConsumptionEnd != null)
+ && (keyValidityForConsumptionEnd.getTime() == Long.MAX_VALUE)) {
+ keyValidityForConsumptionEnd = null;
+ }
+
+ int swEnforcedUserAuthenticatorIds =
+ keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+ int hwEnforcedUserAuthenticatorIds =
+ keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+ int userAuthenticatorIds = swEnforcedUserAuthenticatorIds | hwEnforcedUserAuthenticatorIds;
+ Set<Integer> userAuthenticators =
+ KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(userAuthenticatorIds);
+ Set<Integer> teeBackedUserAuthenticators =
+ KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
+ hwEnforcedUserAuthenticatorIds);
+
+ // TODO: Populate the value below from key characteristics once Keymaster is ready.
+ boolean invalidatedOnNewFingerprintEnrolled = false;
+
+ return new KeyStoreKeySpec(entryAlias,
+ origin,
+ keySize,
+ keyValidityStart,
+ keyValidityForOriginationEnd,
+ keyValidityForConsumptionEnd,
+ purposes,
+ algorithm,
+ padding,
+ digest,
+ blockMode,
+ KeymasterUtils.getInt(keyCharacteristics,
+ KeymasterDefs.KM_TAG_MIN_SECONDS_BETWEEN_OPS),
+ KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT),
+ userAuthenticators,
+ teeBackedUserAuthenticators,
+ KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT),
+ invalidatedOnNewFingerprintEnrolled);
+ }
+
+ @Override
+ protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
+ throw new UnsupportedOperationException(
+ "Key import into Android KeyStore is not supported");
+ }
+
+ @Override
+ protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
+ throw new UnsupportedOperationException(
+ "Key import into Android KeyStore is not supported");
+ }
+}
diff --git a/keystore/java/android/security/KeymasterException.java b/keystore/java/android/security/KeymasterException.java
index 4ff7115..484be12 100644
--- a/keystore/java/android/security/KeymasterException.java
+++ b/keystore/java/android/security/KeymasterException.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.security;
/**
@@ -7,7 +23,14 @@
*/
public class KeymasterException extends Exception {
- public KeymasterException(String message) {
+ private final int mErrorCode;
+
+ public KeymasterException(int errorCode, String message) {
super(message);
+ mErrorCode = errorCode;
+ }
+
+ public int getErrorCode() {
+ return mErrorCode;
}
}
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index e6e88c7..c3092d5 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -1,21 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.security;
+import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterDefs;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
/**
* @hide
*/
public abstract class KeymasterUtils {
private KeymasterUtils() {}
- public static KeymasterException getExceptionForKeymasterError(int keymasterErrorCode) {
+ public static KeymasterException getKeymasterException(int keymasterErrorCode) {
switch (keymasterErrorCode) {
case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
// The name of this parameter significantly differs between Keymaster and framework
// APIs. Use the framework wording to make life easier for developers.
- return new KeymasterException("Invalid user authentication validity duration");
+ return new KeymasterException(keymasterErrorCode,
+ "Invalid user authentication validity duration");
default:
- return new KeymasterException(KeymasterDefs.getErrorMessage(keymasterErrorCode));
+ return new KeymasterException(keymasterErrorCode,
+ KeymasterDefs.getErrorMessage(keymasterErrorCode));
+ }
+ }
+
+ public static CryptoOperationException getCryptoOperationException(KeymasterException e) {
+ switch (e.getErrorCode()) {
+ case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
+ return new UserNotAuthenticatedException();
+ // TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled"
+ // case KeymasterDefs.KM_ERROR_TBD
+ // return new NewFingerprintEnrolledException();
+ default:
+ return new CryptoOperationException("Crypto operation failed", e);
+ }
+ }
+
+ public static CryptoOperationException getCryptoOperationException(int keymasterErrorCode) {
+ return getCryptoOperationException(getKeymasterException(keymasterErrorCode));
+ }
+
+ public static Integer getInt(KeyCharacteristics keyCharacteristics, int tag) {
+ if (keyCharacteristics.hwEnforced.containsTag(tag)) {
+ return keyCharacteristics.hwEnforced.getInt(tag, -1);
+ } else if (keyCharacteristics.swEnforced.containsTag(tag)) {
+ return keyCharacteristics.swEnforced.getInt(tag, -1);
+ } else {
+ return null;
+ }
+ }
+
+ public static List<Integer> getInts(KeyCharacteristics keyCharacteristics, int tag) {
+ List<Integer> result = new ArrayList<Integer>();
+ result.addAll(keyCharacteristics.hwEnforced.getInts(tag));
+ result.addAll(keyCharacteristics.swEnforced.getInts(tag));
+ return result;
+ }
+
+ public static Date getDate(KeyCharacteristics keyCharacteristics, int tag) {
+ Date result = keyCharacteristics.hwEnforced.getDate(tag, null);
+ if (result == null) {
+ result = keyCharacteristics.swEnforced.getDate(tag, null);
+ }
+ return result;
+ }
+
+ public static boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
+ if (keyCharacteristics.hwEnforced.containsTag(tag)) {
+ return keyCharacteristics.hwEnforced.getBoolean(tag, false);
+ } else {
+ return keyCharacteristics.swEnforced.getBoolean(tag, false);
}
}
}
diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java
new file mode 100644
index 0000000..6da4a2a
--- /dev/null
+++ b/keystore/java/android/security/NewFingerprintEnrolledException.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates that a cryptographic operation could not be performed because the key used by the
+ * operation is permanently invalid because a new fingerprint was enrolled.
+ *
+ * @hide
+ */
+public class NewFingerprintEnrolledException extends CryptoOperationException {
+
+ /**
+ * Constructs a new {@code NewFingerprintEnrolledException} without detail message and cause.
+ */
+ public NewFingerprintEnrolledException() {
+ super("Invalid key: new fingerprint enrolled");
+ }
+
+ /**
+ * Constructs a new {@code NewFingerprintEnrolledException} with the provided detail message and
+ * no cause.
+ */
+ public NewFingerprintEnrolledException(String message) {
+ super(message);
+ }
+}
diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java
new file mode 100644
index 0000000..b45817c
--- /dev/null
+++ b/keystore/java/android/security/UserNotAuthenticatedException.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates that a cryptographic operation could not be performed because the user has not been
+ * authenticated recently enough.
+ *
+ * @hide
+ */
+public class UserNotAuthenticatedException extends CryptoOperationException {
+ public UserNotAuthenticatedException() {
+ super("User not authenticated");
+ }
+
+ public UserNotAuthenticatedException(String message) {
+ super(message);
+ }
+}
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 852204a..eb520b4 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -234,7 +234,7 @@
bool ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
enterRegionMode();
mClipRegion.op(region, op);
- setClipRectToRegionBounds();
+ onClipRegionUpdated();
return true;
}
@@ -263,6 +263,9 @@
bool ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op) {
+ // TODO: we should be able to handle kReplace_Op efficiently without
+ // going through RegionMode and later falling back into RectangleMode.
+
if (op != SkRegion::kIntersect_Op) {
enterRegionMode();
return regionModeClipRectWithTransform(r, transform, op);
@@ -324,15 +327,16 @@
*/
void ClipArea::enterRegionMode() {
- if (mMode != kModeRegion) {
- if (mMode == kModeRectangle) {
+ Mode oldMode = mMode;
+ mMode = kModeRegion;
+ if (oldMode != kModeRegion) {
+ if (oldMode == kModeRectangle) {
mClipRegion.setRect(mClipRect.left, mClipRect.top,
mClipRect.right, mClipRect.bottom);
} else {
mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
- setClipRectToRegionBounds();
+ onClipRegionUpdated();
}
- mMode = kModeRegion;
}
}
@@ -342,7 +346,7 @@
SkRegion transformedRectRegion;
regionFromPath(transformedRect, transformedRectRegion);
mClipRegion.op(transformedRectRegion, op);
- setClipRectToRegionBounds();
+ onClipRegionUpdated();
return true;
}
@@ -352,12 +356,13 @@
transform, op);
}
-void ClipArea::setClipRectToRegionBounds() {
+void ClipArea::onClipRegionUpdated() {
if (!mClipRegion.isEmpty()) {
mClipRect.set(mClipRegion.getBounds());
if (mClipRegion.isRect()) {
mClipRegion.setEmpty();
+ enterRectangleMode();
}
} else {
mClipRect.setEmpty();
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 16e6df9..e284af0 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -144,7 +144,7 @@
float bottom, const mat4* transform, SkRegion::Op op);
void ensureClipRegion();
- void setClipRectToRegionBounds();
+ void onClipRegionUpdated();
bool clipRegionOp(float left, float top, float right, float bottom,
SkRegion::Op op);
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 7df61f27..65be9e1 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -16,8 +16,12 @@
#include "JankTracker.h"
#include <algorithm>
+#include <cutils/ashmem.h>
+#include <cutils/log.h>
#include <cstdio>
+#include <errno.h>
#include <inttypes.h>
+#include <sys/mman.h>
namespace android {
namespace uirenderer {
@@ -63,11 +67,114 @@
= FrameInfoFlags::kWindowLayoutChanged
| FrameInfoFlags::kSurfaceCanvas;
+// The bucketing algorithm controls so to speak
+// If a frame is <= to this it goes in bucket 0
+static const uint32_t kBucketMinThreshold = 7;
+// If a frame is > this, start counting in increments of 2ms
+static const uint32_t kBucket2msIntervals = 32;
+// If a frame is > this, start counting in increments of 4ms
+static const uint32_t kBucket4msIntervals = 48;
+
+// This will be called every frame, performance sensitive
+// Uses bit twiddling to avoid branching while achieving the packing desired
+static uint32_t frameCountIndexForFrameTime(nsecs_t frameTime, uint32_t max) {
+ uint32_t index = static_cast<uint32_t>(ns2ms(frameTime));
+ // If index > kBucketMinThreshold mask will be 0xFFFFFFFF as a result
+ // of negating 1 (twos compliment, yaay) else mask will be 0
+ uint32_t mask = -(index > kBucketMinThreshold);
+ // If index > threshold, this will essentially perform:
+ // amountAboveThreshold = index - threshold;
+ // index = threshold + (amountAboveThreshold / 2)
+ // However if index is <= this will do nothing. It will underflow, do
+ // a right shift by 0 (no-op), then overflow back to the original value
+ index = ((index - kBucket4msIntervals) >> (index > kBucket4msIntervals))
+ + kBucket4msIntervals;
+ index = ((index - kBucket2msIntervals) >> (index > kBucket2msIntervals))
+ + kBucket2msIntervals;
+ // If index was < minThreshold at the start of all this it's going to
+ // be a pretty garbage value right now. However, mask is 0 so we'll end
+ // up with the desired result of 0.
+ index = (index - kBucketMinThreshold) & mask;
+ return index < max ? index : max;
+}
+
+// Only called when dumping stats, less performance sensitive
+static uint32_t frameTimeForFrameCountIndex(uint32_t index) {
+ index = index + kBucketMinThreshold;
+ if (index > kBucket2msIntervals) {
+ index += (index - kBucket2msIntervals);
+ }
+ if (index > kBucket4msIntervals) {
+ // This works because it was already doubled by the above if
+ // 1 is added to shift slightly more towards the middle of the bucket
+ index += (index - kBucket4msIntervals) + 1;
+ }
+ return index;
+}
+
JankTracker::JankTracker(nsecs_t frameIntervalNanos) {
+ // By default this will use malloc memory. It may be moved later to ashmem
+ // if there is shared space for it and a request comes in to do that.
+ mData = new ProfileData;
reset();
setFrameInterval(frameIntervalNanos);
}
+JankTracker::~JankTracker() {
+ freeData();
+}
+
+void JankTracker::freeData() {
+ if (mIsMapped) {
+ munmap(mData, sizeof(ProfileData));
+ } else {
+ delete mData;
+ }
+ mIsMapped = false;
+ mData = nullptr;
+}
+
+void JankTracker::switchStorageToAshmem(int ashmemfd) {
+ int regionSize = ashmem_get_size_region(ashmemfd);
+ if (regionSize < static_cast<int>(sizeof(ProfileData))) {
+ ALOGW("Ashmem region is too small! Received %d, required %u",
+ regionSize, static_cast<unsigned int>(sizeof(ProfileData)));
+ return;
+ }
+ ProfileData* newData = reinterpret_cast<ProfileData*>(
+ mmap(NULL, sizeof(ProfileData), PROT_READ | PROT_WRITE,
+ MAP_SHARED, ashmemfd, 0));
+ if (newData == MAP_FAILED) {
+ int err = errno;
+ ALOGW("Failed to move profile data to ashmem fd %d, error = %d",
+ ashmemfd, err);
+ return;
+ }
+
+ // The new buffer may have historical data that we want to build on top of
+ // But let's make sure we don't overflow Just In Case
+ uint32_t divider = 0;
+ if (newData->totalFrameCount > (1 << 24)) {
+ divider = 4;
+ }
+ for (size_t i = 0; i < mData->jankTypeCounts.size(); i++) {
+ newData->jankTypeCounts[i] >>= divider;
+ newData->jankTypeCounts[i] += mData->jankTypeCounts[i];
+ }
+ for (size_t i = 0; i < mData->frameCounts.size(); i++) {
+ newData->frameCounts[i] >>= divider;
+ newData->frameCounts[i] += mData->frameCounts[i];
+ }
+ newData->jankFrameCount >>= divider;
+ newData->jankFrameCount += mData->jankFrameCount;
+ newData->totalFrameCount >>= divider;
+ newData->totalFrameCount += mData->totalFrameCount;
+
+ freeData();
+ mData = newData;
+ mIsMapped = true;
+}
+
void JankTracker::setFrameInterval(nsecs_t frameInterval) {
mFrameInterval = frameInterval;
mThresholds[kMissedVsync] = 1;
@@ -92,16 +199,15 @@
}
void JankTracker::addFrame(const FrameInfo& frame) {
- mTotalFrameCount++;
+ mData->totalFrameCount++;
// Fast-path for jank-free frames
int64_t totalDuration =
frame[FrameInfoIndex::kFrameCompleted] - frame[FrameInfoIndex::kIntendedVsync];
- uint32_t framebucket = std::min(
- static_cast<typeof mFrameCounts.size()>(ns2ms(totalDuration)),
- mFrameCounts.size());
+ uint32_t framebucket = frameCountIndexForFrameTime(
+ totalDuration, mData->frameCounts.size());
// Keep the fast path as fast as possible.
if (CC_LIKELY(totalDuration < mFrameInterval)) {
- mFrameCounts[framebucket]++;
+ mData->frameCounts[framebucket]++;
return;
}
@@ -109,47 +215,52 @@
return;
}
- mFrameCounts[framebucket]++;
- mJankFrameCount++;
+ mData->frameCounts[framebucket]++;
+ mData->jankFrameCount++;
for (int i = 0; i < NUM_BUCKETS; i++) {
int64_t delta = frame[COMPARISONS[i].end] - frame[COMPARISONS[i].start];
if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) {
- mBuckets[i].count++;
+ mData->jankTypeCounts[i]++;
}
}
}
-void JankTracker::dump(int fd) {
- FILE* file = fdopen(fd, "a");
- fprintf(file, "\nFrame stats:");
- fprintf(file, "\n Total frames rendered: %u", mTotalFrameCount);
- fprintf(file, "\n Janky frames: %u (%.2f%%)", mJankFrameCount,
- (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f);
- fprintf(file, "\n 90th percentile: %ums", findPercentile(90));
- fprintf(file, "\n 95th percentile: %ums", findPercentile(95));
- fprintf(file, "\n 99th percentile: %ums", findPercentile(99));
- for (int i = 0; i < NUM_BUCKETS; i++) {
- fprintf(file, "\n Number %s: %u", JANK_TYPE_NAMES[i], mBuckets[i].count);
+void JankTracker::dumpBuffer(const void* buffer, size_t bufsize, int fd) {
+ if (bufsize < sizeof(ProfileData)) {
+ return;
}
- fprintf(file, "\n");
- fflush(file);
+ const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer);
+ dumpData(data, fd);
+}
+
+void JankTracker::dumpData(const ProfileData* data, int fd) {
+ dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
+ dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
+ (float) data->jankFrameCount / (float) data->totalFrameCount * 100.0f);
+ dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
+ dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
+ dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
+ for (int i = 0; i < NUM_BUCKETS; i++) {
+ dprintf(fd, "\nNumber %s: %u", JANK_TYPE_NAMES[i], data->jankTypeCounts[i]);
+ }
+ dprintf(fd, "\n");
}
void JankTracker::reset() {
- mBuckets.fill({0});
- mFrameCounts.fill(0);
- mTotalFrameCount = 0;
- mJankFrameCount = 0;
+ mData->jankTypeCounts.fill(0);
+ mData->frameCounts.fill(0);
+ mData->totalFrameCount = 0;
+ mData->jankFrameCount = 0;
}
-uint32_t JankTracker::findPercentile(int percentile) {
- int pos = percentile * mTotalFrameCount / 100;
- int remaining = mTotalFrameCount - pos;
- for (int i = mFrameCounts.size() - 1; i >= 0; i--) {
- remaining -= mFrameCounts[i];
+uint32_t JankTracker::findPercentile(const ProfileData* data, int percentile) {
+ int pos = percentile * data->totalFrameCount / 100;
+ int remaining = data->totalFrameCount - pos;
+ for (int i = data->frameCounts.size() - 1; i >= 0; i--) {
+ remaining -= data->frameCounts[i];
if (remaining <= 0) {
- return i;
+ return frameTimeForFrameCountIndex(i);
}
}
return 0;
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index ae339ec..4783001 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -20,6 +20,8 @@
#include "renderthread/TimeLord.h"
#include "utils/RingBuffer.h"
+#include <cutils/compiler.h>
+
#include <array>
#include <memory>
@@ -37,33 +39,45 @@
NUM_BUCKETS,
};
-struct JankBucket {
- // Number of frames that hit this bucket
- uint32_t count;
+// Try to keep as small as possible, should match ASHMEM_SIZE in
+// GraphicsStatsService.java
+struct ProfileData {
+ std::array<uint32_t, NUM_BUCKETS> jankTypeCounts;
+ // See comments on kBucket* constants for what this holds
+ std::array<uint32_t, 57> frameCounts;
+
+ uint32_t totalFrameCount;
+ uint32_t jankFrameCount;
};
// TODO: Replace DrawProfiler with this
class JankTracker {
public:
JankTracker(nsecs_t frameIntervalNanos);
-
- void setFrameInterval(nsecs_t frameIntervalNanos);
+ ~JankTracker();
void addFrame(const FrameInfo& frame);
- void dump(int fd);
+ void dump(int fd) { dumpData(mData, fd); }
void reset();
+ void switchStorageToAshmem(int ashmemfd);
+
+ uint32_t findPercentile(int p) { return findPercentile(mData, p); }
+
+ ANDROID_API static void dumpBuffer(const void* buffer, size_t bufsize, int fd);
+
private:
- uint32_t findPercentile(int p);
+ void freeData();
+ void setFrameInterval(nsecs_t frameIntervalNanos);
- std::array<JankBucket, NUM_BUCKETS> mBuckets;
+ static uint32_t findPercentile(const ProfileData* data, int p);
+ static void dumpData(const ProfileData* data, int fd);
+
std::array<int64_t, NUM_BUCKETS> mThresholds;
- std::array<uint32_t, 128> mFrameCounts;
-
int64_t mFrameInterval;
- uint32_t mTotalFrameCount;
- uint32_t mJankFrameCount;
+ ProfileData* mData;
+ bool mIsMapped = false;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 3781969..02fbd89 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -858,6 +858,8 @@
.setModelViewMapUnitToRectOptionalSnap(snap, rect)
.setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
+ renderGlop(glop);
+ return;
}
float alpha = getLayerAlpha(layer);
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9456073..9237151 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -41,15 +41,10 @@
RenderNode* rootRenderNode, IContextFactory* contextFactory)
: mRenderThread(thread)
, mEglManager(thread.eglManager())
- , mEglSurface(EGL_NO_SURFACE)
- , mBufferPreserved(false)
- , mSwapBehavior(kSwap_default)
, mOpaque(!translucent)
- , mCanvas(nullptr)
- , mHaveNewSurface(false)
, mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
, mRootRenderNode(rootRenderNode)
- , mCurrentFrameInfo(nullptr) {
+ , mJankTracker(thread.timeLord().frameIntervalNanos()) {
mRenderThread.renderState().registerCanvasContext(this);
mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
}
@@ -258,6 +253,7 @@
// TODO: Use a fence for real completion?
mCurrentFrameInfo->markFrameCompleted();
+ mJankTracker.addFrame(*mCurrentFrameInfo);
mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
profiler().finishFrame();
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index c3904c2..f5f1f54 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -127,23 +127,24 @@
RenderThread& mRenderThread;
EglManager& mEglManager;
sp<ANativeWindow> mNativeWindow;
- EGLSurface mEglSurface;
- bool mBufferPreserved;
- SwapBehavior mSwapBehavior;
+ EGLSurface mEglSurface = EGL_NO_SURFACE;
+ bool mBufferPreserved = false;
+ SwapBehavior mSwapBehavior = kSwap_default;
bool mOpaque;
- OpenGLRenderer* mCanvas;
- bool mHaveNewSurface;
+ OpenGLRenderer* mCanvas = nullptr;
+ bool mHaveNewSurface = false;
DamageAccumulator mDamageAccumulator;
std::unique_ptr<AnimationContext> mAnimationContext;
const sp<RenderNode> mRootRenderNode;
DrawProfiler mProfiler;
- FrameInfo* mCurrentFrameInfo;
+ FrameInfo* mCurrentFrameInfo = nullptr;
// Ring buffer large enough for 1 second worth of frames
RingBuffer<FrameInfo, 60> mFrames;
std::string mName;
+ JankTracker mJankTracker;
std::set<RenderNode*> mPrefetechedLayers;
};
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 0091790..cc87241 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -441,6 +441,19 @@
post(task);
}
+CREATE_BRIDGE2(setProcessStatsBuffer, RenderThread* thread, int fd) {
+ args->thread->jankTracker().switchStorageToAshmem(args->fd);
+ close(args->fd);
+ return nullptr;
+}
+
+void RenderProxy::setProcessStatsBuffer(int fd) {
+ SETUP_TASK(setProcessStatsBuffer);
+ args->thread = &mRenderThread;
+ args->fd = dup(fd);
+ post(task);
+}
+
void RenderProxy::post(RenderTask* task) {
mRenderThread.queue(task);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 43cbe07..29c6f08 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -99,6 +99,7 @@
ANDROID_API static void dumpGraphicsMemory(int fd);
ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
+ ANDROID_API void setProcessStatsBuffer(int fd);
private:
RenderThread& mRenderThread;
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index c05fd77..c49e8c2 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -40,6 +40,12 @@
private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;
+ /**
+ * Accessed by native methods: JNI Callback context.
+ */
+ @SuppressWarnings("unused")
+ private long mJniCallback;
+
void init() {
synchronized (this) {
if (mHandler != null) {
@@ -63,9 +69,6 @@
listeners = mListeners;
}
}
- if (listeners.isEmpty()) {
- return;
- }
// reset audio port cache if the event corresponds to a change coming
// from audio policy service or if mediaserver process died.
if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED ||
@@ -73,6 +76,11 @@
msg.what == AUDIOPORT_EVENT_SERVICE_DIED) {
AudioManager.resetAudioPortGeneration();
}
+
+ if (listeners.isEmpty()) {
+ return;
+ }
+
ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index d77fcd8..83954ae 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2602,15 +2602,21 @@
return;
case MEDIA_STOPPED:
- if (mTimeProvider != null) {
- mTimeProvider.onStopped();
+ {
+ TimeProvider timeProvider = mTimeProvider;
+ if (timeProvider != null) {
+ timeProvider.onStopped();
+ }
}
break;
case MEDIA_STARTED:
case MEDIA_PAUSED:
- if (mTimeProvider != null) {
- mTimeProvider.onPaused(msg.what == MEDIA_PAUSED);
+ {
+ TimeProvider timeProvider = mTimeProvider;
+ if (timeProvider != null) {
+ timeProvider.onPaused(msg.what == MEDIA_PAUSED);
+ }
}
break;
@@ -2620,21 +2626,26 @@
return;
case MEDIA_SEEK_COMPLETE:
- if (mOnSeekCompleteListener != null) {
- mOnSeekCompleteListener.onSeekComplete(mMediaPlayer);
- }
- // fall through
+ if (mOnSeekCompleteListener != null) {
+ mOnSeekCompleteListener.onSeekComplete(mMediaPlayer);
+ }
+ // fall through
case MEDIA_SKIPPED:
- if (mTimeProvider != null) {
- mTimeProvider.onSeekComplete(mMediaPlayer);
- }
- return;
+ {
+ TimeProvider timeProvider = mTimeProvider;
+ if (timeProvider != null) {
+ timeProvider.onSeekComplete(mMediaPlayer);
+ }
+ }
+ return;
case MEDIA_SET_VIDEO_SIZE:
- if (mOnVideoSizeChangedListener != null)
- mOnVideoSizeChangedListener.onVideoSizeChanged(mMediaPlayer, msg.arg1, msg.arg2);
- return;
+ if (mOnVideoSizeChangedListener != null) {
+ mOnVideoSizeChangedListener.onVideoSizeChanged(
+ mMediaPlayer, msg.arg1, msg.arg2);
+ }
+ return;
case MEDIA_ERROR:
Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 1255276..9ea6722 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -553,15 +553,8 @@
boolean isimage = MediaFile.isImageFileType(mFileType);
if (isaudio || isvideo || isimage) {
- if (mExternalIsEmulated && path.startsWith(mExternalStoragePath)) {
- // try to rewrite the path to bypass the sd card fuse layer
- String directPath = Environment.getMediaStorageDirectory() +
- path.substring(mExternalStoragePath.length());
- File f = new File(directPath);
- if (f.exists()) {
- path = directPath;
- }
- }
+ path = Environment.maybeTranslateEmulatedPathToInternal(new File(path))
+ .getAbsolutePath();
}
// we only extract metadata for audio and video files
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index e20eabc..7b8102b 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -59,7 +59,7 @@
*
* @return the storage ID
*/
- public static int getStorageId(int index) {
+ public static int getStorageIdForIndex(int index) {
// storage ID is 0x00010001 for primary storage,
// then 0x00020001, 0x00030001, etc. for secondary storages
return ((index + 1) << 16) + 1;
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 9fc7e8e..708c083 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -431,6 +431,19 @@
pData = buffer->data;
dataSize = buffer->stride * buffer->height;
break;
+ case HAL_PIXEL_FORMAT_RAW12:
+ // Single plane 10bpp bayer data.
+ ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
+ LOG_ALWAYS_FATAL_IF(buffer->width % 4,
+ "Width is not multiple of 4 %d", buffer->width);
+ LOG_ALWAYS_FATAL_IF(buffer->height % 2,
+ "Height is not even %d", buffer->height);
+ LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 12 / 8),
+ "stride (%d) should be at least %d",
+ buffer->stride, buffer->width * 12 / 8);
+ pData = buffer->data;
+ dataSize = buffer->stride * buffer->height;
+ break;
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGBX_8888:
// Single plane, 32bpp.
@@ -492,8 +505,10 @@
break;
case HAL_PIXEL_FORMAT_BLOB:
case HAL_PIXEL_FORMAT_RAW10:
- // Blob is used for JPEG data, RAW10 is used for 10-bit raw data, they are
- // single plane, row and pixel strides are 0.
+ case HAL_PIXEL_FORMAT_RAW12:
+ // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
+ // those are single plane data with pixel stride 0 since they don't really have a
+ // well defined pixel stride
ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
pixelStride = 0;
break;
@@ -549,12 +564,14 @@
rowStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
break;
case HAL_PIXEL_FORMAT_BLOB:
- // Blob is used for JPEG data, RAW10 is used for 10-bit raw data, they are
- // single plane, row and pixel strides are 0.
+ // Blob is used for JPEG data. It is single plane and has 0 row stride and
+ // 0 pixel stride
ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
rowStride = 0;
break;
case HAL_PIXEL_FORMAT_RAW10:
+ case HAL_PIXEL_FORMAT_RAW12:
+ // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
rowStride = buffer->stride;
break;
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 10233f3..25c6154 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -716,7 +716,15 @@
}
#endif
- if (!mAudioTrack.get() || mPrevSampleID != sample->sampleID()) {
+ // check if the existing track has the same sample id.
+ if (mAudioTrack != 0 && mPrevSampleID == sample->sampleID()) {
+ // the sample rate may fail to change if the audio track is a fast track.
+ if (mAudioTrack->setSampleRate(sampleRate) == NO_ERROR) {
+ newTrack = mAudioTrack;
+ ALOGV("reusing track %p for sample %d", mAudioTrack.get(), sample->sampleID());
+ }
+ }
+ if (newTrack == 0) {
// mToggle toggles each time a track is started on a given channel.
// The toggle is concatenated with the SoundChannel address and passed to AudioTrack
// as callback user data. This enables the detection of callbacks received from the old
@@ -746,10 +754,6 @@
mToggle = toggle;
mAudioTrack = newTrack;
ALOGV("using new track %p for sample %d", newTrack.get(), sample->sampleID());
- } else {
- newTrack = mAudioTrack;
- newTrack->setSampleRate(sampleRate);
- ALOGV("reusing track %p for sample %d", mAudioTrack.get(), sample->sampleID());
}
newTrack->setVolume(leftVolume, rightVolume);
newTrack->setLoop(0, frameCount, loop);
diff --git a/packages/DocumentsUI/res/menu/mode_directory.xml b/packages/DocumentsUI/res/menu/mode_directory.xml
index 0a3645f..695060d 100644
--- a/packages/DocumentsUI/res/menu/mode_directory.xml
+++ b/packages/DocumentsUI/res/menu/mode_directory.xml
@@ -29,4 +29,8 @@
android:icon="@drawable/ic_menu_delete"
android:title="@string/menu_delete"
android:showAsAction="always" />
+ <item
+ android:id="@+id/menu_select_all"
+ android:title="@string/menu_select_all"
+ android:showAsAction="never" />
</menu>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 19fe7a7..98e2b2f 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Deel"</string>
<string name="menu_delete" msgid="8138799623850614177">"Vee uit"</string>
<string name="menu_select" msgid="8711270657353563424">"Kies \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Wys interne berging"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Wys SD-kaart"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Versteek interne berging"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index 419d162..88865bc 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"አጋራ"</string>
<string name="menu_delete" msgid="8138799623850614177">"ሰርዝ"</string>
<string name="menu_select" msgid="8711270657353563424">"«<xliff:g id="DIRECTORY">^1</xliff:g>»ን ይምረጡ"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ውስጣዊ ማከማቻ አሳይ"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD ካርድ አሳይ"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ውስጣዊ ማከማቻ ደብቅ"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 5bccdae..5162241 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"مشاركة"</string>
<string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
<string name="menu_select" msgid="8711270657353563424">"تحديد \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"إظهار وحدة التخزين الداخلية"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"إظهار بطاقة SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"إخفاء وحدة التخزين الداخلية"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 77f6855..14726eb 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Споделяне"</string>
<string name="menu_delete" msgid="8138799623850614177">"Изтриване"</string>
<string name="menu_select" msgid="8711270657353563424">"Избиране на „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Вътр. хранилище: Показв."</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD карта: Показване"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Вътр. хранилище: Скрив."</string>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 603cb96..55fe9c7 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"ভাগ করুন"</string>
<string name="menu_delete" msgid="8138799623850614177">"মুছুন"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" নির্বাচন করুন"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"অভ্যন্তরীণ সঞ্চয়স্থান দেখান"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD কার্ড দেখান"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"অভ্যন্তরীণ সঞ্চয়স্থান লুকান"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index d973650..a4d4a51 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Comparteix"</string>
<string name="menu_delete" msgid="8138799623850614177">"Suprimeix"</string>
<string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostra emmagatz. intern"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostra la targeta SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Amaga emmagatz. intern"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index 36bb72f..7261849 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Sdílet"</string>
<string name="menu_delete" msgid="8138799623850614177">"Smazat"</string>
<string name="menu_select" msgid="8711270657353563424">"Vyberte adresář <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Zobrazit inter. úložiště"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Zobrazit SD kartu"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skrýt interní úložiště"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 5feb517..f4e59b0 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Del"</string>
<string name="menu_delete" msgid="8138799623850614177">"Slet"</string>
<string name="menu_select" msgid="8711270657353563424">"Vælg \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Vis intern lagerplads"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Vis SD-kort"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skjul intern lagerplads"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index 598862b..b0e4a14 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Teilen"</string>
<string name="menu_delete" msgid="8138799623850614177">"Löschen"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" auswählen"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Int. Speicher anzeigen"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD-Karte anzeigen"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Int. Speicher ausblenden"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 37f99cf..2188dc2 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Κοινή χρήση"</string>
<string name="menu_delete" msgid="8138799623850614177">"Διαγραφή"</string>
<string name="menu_select" msgid="8711270657353563424">"Επιλογή \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Εμφ.εσωτ.χώρου αποθήκ."</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Εμφάνιση κάρτας SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Απόκρ.εσωτ.χώρου αποθήκ."</string>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 2bd5615..89257a1 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Share"</string>
<string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
<string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Show SD card"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Hide internal storage"</string>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 2bd5615..89257a1 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Share"</string>
<string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
<string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Show SD card"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Hide internal storage"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 2bd5615..89257a1 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Share"</string>
<string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
<string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Show SD card"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Hide internal storage"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 4a47b73..693a981 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
<string name="menu_select" msgid="8711270657353563424">"Seleccionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almacen. interno"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar tarjeta SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar almacen. interno"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 95cc812..422c47c 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
<string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almac. interno"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar tarjeta SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar almac. interno"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index c98f0b9..cce47c1 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Jaga"</string>
<string name="menu_delete" msgid="8138799623850614177">"Kustuta"</string>
<string name="menu_select" msgid="8711270657353563424">"Kataloogi „<xliff:g id="DIRECTORY">^1</xliff:g>” valimine"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Kuva sis. salvestusruum"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Kuva SD-kaart"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Peida sis. salvestusruum"</string>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 1fd7b1d..4e0735a 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Partekatu"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ezabatu"</string>
<string name="menu_select" msgid="8711270657353563424">"Hautatu \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Erakutsi barneko memoria"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Erakutsi SD txartela"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ezkutatu barneko memoria"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 6c57211..b8874b8 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"اشتراکگذاری"</string>
<string name="menu_delete" msgid="8138799623850614177">"حذف"</string>
<string name="menu_select" msgid="8711270657353563424">"انتخاب «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"نمایش فضای ذخیرهسازی داخلی"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"نمایش کارت SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"پنهان کردن فضای ذخیرهسازی داخلی"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 185be47..74a0beb 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Jaa"</string>
<string name="menu_delete" msgid="8138799623850614177">"Poista"</string>
<string name="menu_select" msgid="8711270657353563424">"Valitse <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Näytä sis. tallennustila"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Näytä SD-kortti"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Piilota sis. tallennust."</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 4e4c0ed..00e09a2 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Partager"</string>
<string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
<string name="menu_select" msgid="8711270657353563424">"Sélectionner « <xliff:g id="DIRECTORY">^1</xliff:g> »"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Aff. mém. stock. interne"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Afficher la carte SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Masquer mém. stock. int."</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index b760caa..5b4b2d8 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Partager"</string>
<string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
<string name="menu_select" msgid="8711270657353563424">"Sélectionner \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Aff. mém. stock. interne"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Afficher la carte SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Masquer mém. stock. int."</string>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index bc6ee9e..91199e6 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
<string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almacen. interno"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar tarxeta SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar almacen. interno"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 88f26ed..5f122f8 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"साझा करें"</string>
<string name="menu_delete" msgid="8138799623850614177">"हटाएं"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" चुनें"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"आंतरिक मेमोरी दिखाएं"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD कार्ड दिखाएं"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"आंतरिक मेमोरी छिपाएं"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 60343d2..35c8508 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Dijeli"</string>
<string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
<string name="menu_select" msgid="8711270657353563424">"Odaberi \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaži internu pohranu"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Pokaži SD karticu"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Sakrij internu pohranu"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index a9b5a7c..334e2a0 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Megosztás"</string>
<string name="menu_delete" msgid="8138799623850614177">"Törlés"</string>
<string name="menu_select" msgid="8711270657353563424">"A(z) „<xliff:g id="DIRECTORY">^1</xliff:g>” mappa kiválasztása"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Belső tárhely"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD-kártya megjelenítése"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Belső tárhely elrejtése"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 487f5bd..1040fd2 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Համօգտագործել"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ջնջել"</string>
<string name="menu_select" msgid="8711270657353563424">"Ընտրել «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ցույց տալ ներքին պահոցը"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Ցույց տալ SD քարտը"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Թաքցնել ներքին պահոցը"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 1514fc6..a8c62da 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Bagikan"</string>
<string name="menu_delete" msgid="8138799623850614177">"Hapus"</string>
<string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Tampilkan simpanan internal"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Tampilkan kartu SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Sembunyikan simpanan internal"</string>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index f324dad..b81b024 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Deila"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eyða"</string>
<string name="menu_select" msgid="8711270657353563424">"Velja „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Sýna innbyggða geymslu"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Sýna SD-kort"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Fela innbyggða geymslu"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index a073c44..fa5743f 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Condividi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Elimina"</string>
<string name="menu_select" msgid="8711270657353563424">"Seleziona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostra memoria interna"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostra scheda SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Nascondi memoria interna"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 6ab2880..92a0bf47cf 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"שתף"</string>
<string name="menu_delete" msgid="8138799623850614177">"מחק"</string>
<string name="menu_select" msgid="8711270657353563424">"בחר ב-\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"הצג אחסון פנימי"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"הצג כרטיס SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"הסתר אחסון פנימי"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index f57a21c..938dfa4 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"共有"</string>
<string name="menu_delete" msgid="8138799623850614177">"削除"</string>
<string name="menu_select" msgid="8711270657353563424">"「<xliff:g id="DIRECTORY">^1</xliff:g>」を選択"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"内部ストレージを表示"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SDカードを表示"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"内部ストレージを非表示"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index b1e39b8..7f33e7c 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"გაზიარება"</string>
<string name="menu_delete" msgid="8138799623850614177">"წაშლა"</string>
<string name="menu_select" msgid="8711270657353563424">"„<xliff:g id="DIRECTORY">^1</xliff:g>“-ის არჩევა"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"შიდა საცავის ჩვენება"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD ბარათის ჩვენება"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"შიდა მეხსიერების დამალვა"</string>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index c7e207c..0d91781 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Бөлісу"</string>
<string name="menu_delete" msgid="8138799623850614177">"Жою"</string>
<string name="menu_select" msgid="8711270657353563424">"«<xliff:g id="DIRECTORY">^1</xliff:g>» таңдау"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ішкі жадты көрсету"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD картасын көрсету"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ішкі жадты жасыру"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 3055001..2b71a57 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"ចែករំលែក"</string>
<string name="menu_delete" msgid="8138799623850614177">"លុប"</string>
<string name="menu_select" msgid="8711270657353563424">"ជ្រើស \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"បង្ហាញឧបករណ៍ផ្ទុកខាងក្នុង"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"បង្ហាញកាតអេសឌី"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"លាក់ឧបករណ៍ផ្ទុកខាងក្នុង"</string>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 508f0e5..ffedf11 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"ಹಂಚು"</string>
<string name="menu_delete" msgid="8138799623850614177">"ಅಳಿಸು"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" ಆಯ್ಕೆಮಾಡಿ"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ಆಂತರಿಕ ಸಂಗ್ರಹಣೆಯನ್ನು ತೋರಿಸು"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD ಕಾಡ್ ಅನ್ನು ತೋರಿಸು"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ಆಂತರಿಕ ಸಂಗ್ರಹಣೆಯನ್ನು ಮರೆಮಾಡಿ"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index d6f0cbd..6b6fc7a 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"공유"</string>
<string name="menu_delete" msgid="8138799623850614177">"삭제"</string>
<string name="menu_select" msgid="8711270657353563424">"\'<xliff:g id="DIRECTORY">^1</xliff:g>\' 선택"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"내부 저장소 표시"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD 카드 표시"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"내부 저장소 숨기기"</string>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index a4f718b..da4049b 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Бөлүшүү"</string>
<string name="menu_delete" msgid="8138799623850614177">"Өчүрүү"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" тандоо"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ички сактагычты көрсөтүү"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD картаны көрсөтүү"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ички эстутумду жашыруу"</string>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 8db69c7..52ae201 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"ແບ່ງປັນ"</string>
<string name="menu_delete" msgid="8138799623850614177">"ລຶບ"</string>
<string name="menu_select" msgid="8711270657353563424">"ເລືອກ \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ສະແດງໂຕເກັບຂໍ້ມູນພາຍໃນ"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"ສະແດງ SD Card"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ເຊື່ອງໂຕເກັບຂໍ້ມູນພາຍໃນ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 81412c5..31e510b 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Bendrinti"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ištrinti"</string>
<string name="menu_select" msgid="8711270657353563424">"Pasirinkti katalogą „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Rodyti vidinę atmintį"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Rodyti SD kortelę"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Slėpti vidinę atmintį"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 0cd5812..93794fa 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Kopīgot"</string>
<string name="menu_delete" msgid="8138799623850614177">"Dzēst"</string>
<string name="menu_select" msgid="8711270657353563424">"Atlasīt “<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Rādīt iekšējo atmiņu"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Rādīt SD karti"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Paslēpt iekšējo atmiņu"</string>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index d909741..6fe9c86 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Сподели"</string>
<string name="menu_delete" msgid="8138799623850614177">"Избриши"</string>
<string name="menu_select" msgid="8711270657353563424">"Одберете „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Прикажи внатрешна мемор."</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Прикажи СД-картичка"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Скриј внатрешна меморија"</string>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index 24f4815..052dbd2 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"പങ്കിടുക"</string>
<string name="menu_delete" msgid="8138799623850614177">"ഇല്ലാതാക്കുക"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" തിരഞ്ഞെടുക്കുക"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ആന്തരിക സംഭരണം കാണിക്കുക"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD കാർഡ് കാണിക്കുക"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ആന്തരിക സംഭരണം മറയ്ക്കുക"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 141032d..737d4b2 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Хуваалцах"</string>
<string name="menu_delete" msgid="8138799623850614177">"Устгах"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\"-г сонгох"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Дотоод санг харуулах"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD картыг харуулах"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Дотоод санг нуух"</string>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index b59ded5..26a65cd 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"सामायिक करा"</string>
<string name="menu_delete" msgid="8138799623850614177">"हटवा"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" निवडा"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"अंतर्गत संचयन दर्शवा"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD कार्ड दर्शवा"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"अंतर्गत संचयन लपवा"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 5330d92..e9de0e3 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Kongsi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Padam"</string>
<string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Papar storan dalaman"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Papar kad SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Sembunyikan storan dlmn"</string>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 50f8363..ae38956 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"မျှဝေခြင်း"</string>
<string name="menu_delete" msgid="8138799623850614177">"ဖျက်ပစ်ရန်"</string>
<string name="menu_select" msgid="8711270657353563424">"ရွေးရန်\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"စက်ရှိစတိုရုံ ပြပါ"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD ကဒ် ပြပါ"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"စက်ရှိစတိုရုံ ဖျောက်ထားပါ"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index beee44f..d10b740 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Del"</string>
<string name="menu_delete" msgid="8138799623850614177">"Slett"</string>
<string name="menu_select" msgid="8711270657353563424">"Velg «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Vis den interne lagringen"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Vis SD-kortet"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skjul den interne lagringen"</string>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index 4251a7c..2b6015a 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"साझेदारी गर्नुहोस्"</string>
<string name="menu_delete" msgid="8138799623850614177">"मेटाउनुहोस्"</string>
<string name="menu_select" msgid="8711270657353563424">"चयनगर्नुहोस् \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"आन्तरिक भण्डारण देखाउनुहोस्"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD कार्ड देखाउनुहोस्"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"आन्तरिक भण्डारण लुकाउनुहोस्"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 1fc7dc1..dc5e250 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Delen"</string>
<string name="menu_delete" msgid="8138799623850614177">"Verwijderen"</string>
<string name="menu_select" msgid="8711270657353563424">"<xliff:g id="DIRECTORY">^1</xliff:g> selecteren"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Interne opslag weergeven"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD-kaart weergeven"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Interne opslag verbergen"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 5bb7f75..eb84e5d 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Udostępnij"</string>
<string name="menu_delete" msgid="8138799623850614177">"Usuń"</string>
<string name="menu_select" msgid="8711270657353563424">"Zaznacz „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaż pamięć wewnętrzną"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Pokaż kartę SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ukryj pamięć wewnętrzną"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index e32dfc9..b0edad6 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Partilhar"</string>
<string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
<string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar mem. armaz. int."</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar cartão SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar mem. armaz. int."</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 2aaa4d2..f35bd19 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Compartilhar"</string>
<string name="menu_delete" msgid="8138799623850614177">"Excluir"</string>
<string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar armaz. interno"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar cartão SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar armaz. interno"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index c5de856..646d537c 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Distribuiți"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ștergeți"</string>
<string name="menu_select" msgid="8711270657353563424">"Selectați „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Afișați stocarea internă"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Afișați cardul SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ascundeți stocarea internă"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 10de6f0..0cc90de 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Поделиться"</string>
<string name="menu_delete" msgid="8138799623850614177">"Удалить"</string>
<string name="menu_select" msgid="8711270657353563424">"Выбрать папку \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Внутренняя память"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD-карта"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Скрыть внутреннюю память"</string>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index 26e2b1d..fe2c66f 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"බෙදාගන්න"</string>
<string name="menu_delete" msgid="8138799623850614177">"මකන්න"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" තෝරන්න"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"අභ්යන්තර ආචයනය පෙන්වන්න"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD කාඩ් පත පෙන්වන්න"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"අභ්යන්තර ආචයනය සඟවන්න"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index facaf4a..b68a493 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Zdieľať"</string>
<string name="menu_delete" msgid="8138799623850614177">"Odstrániť"</string>
<string name="menu_select" msgid="8711270657353563424">"Vyberte adresár <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Zobraziť interné úložisko"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Zobraziť kartu SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skryť interné úložisko"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index 865df8b..f289e64 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Skupna raba"</string>
<string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
<string name="menu_select" msgid="8711270657353563424">"Izbira mape »<xliff:g id="DIRECTORY">^1</xliff:g>«"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaži notranjo shrambo"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Pokaži kartico SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skrij notranjo shrambo"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index fd20722..d18a227 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Дели"</string>
<string name="menu_delete" msgid="8138799623850614177">"Избриши"</string>
<string name="menu_select" msgid="8711270657353563424">"Изабери „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Прикажи интерну меморију"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Прикажи SD картицу"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Сакриј интерну меморију"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index a77b75d..e2d0e2a 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Dela"</string>
<string name="menu_delete" msgid="8138799623850614177">"Ta bort"</string>
<string name="menu_select" msgid="8711270657353563424">"Välj <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Visa internminne"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Visa SD-kort"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Dölj internminne"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index b46d97f..65fe404 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Shiriki"</string>
<string name="menu_delete" msgid="8138799623850614177">"Futa"</string>
<string name="menu_select" msgid="8711270657353563424">"Chagua \" <xliff:g id="DIRECTORY">^1</xliff:g> \""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Onyesha hifadhi ya ndani"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Onyesha kadi ya SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ficha hifadhi ya ndani"</string>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 5b09b97..dc20e84 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"பகிர்"</string>
<string name="menu_delete" msgid="8138799623850614177">"நீக்கு"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" ஐத் தேர்ந்தெடு"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"அகச் சேமிப்பகத்தைக் காட்டு"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD கார்டைக் காட்டு"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"அகச் சேமிப்பகத்தை மறை"</string>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index e04724a..24acc24 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"భాగస్వామ్యం చేయి"</string>
<string name="menu_delete" msgid="8138799623850614177">"తొలగించు"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\"ని ఎంచుకోండి"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"అంతర్గత నిల్వను చూపు"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD కార్డ్ను చూపు"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"అంతర్గత నిల్వను దాచు"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 5410d37..e692cb7 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"แชร์"</string>
<string name="menu_delete" msgid="8138799623850614177">"ลบ"</string>
<string name="menu_select" msgid="8711270657353563424">"เลือก \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"แสดงที่จัดเก็บภายใน"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"แสดงการ์ด SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ซ่อนที่จัดเก็บภายใน"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 3defd6a..e55d552 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Ibahagi"</string>
<string name="menu_delete" msgid="8138799623850614177">"Tanggalin"</string>
<string name="menu_select" msgid="8711270657353563424">"Piliin ang \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ipakita internal storage"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Ipakita ang SD card"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Itago internal storage"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 9f0f846..b80904c 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Paylaş"</string>
<string name="menu_delete" msgid="8138799623850614177">"Sil"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" dizinini seç"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Dahili depolamayı göster"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD kartı göster"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Dahili depolamayı gizle"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 5be1947..77654fd 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Поділитися"</string>
<string name="menu_delete" msgid="8138799623850614177">"Видалити"</string>
<string name="menu_select" msgid="8711270657353563424">"Вибрати каталог \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Показати внутр. пам’ять"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Показати карту SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Сховати внутр. пам’ять"</string>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 729fc7f..d20f14c 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"اشتراک کریں"</string>
<string name="menu_delete" msgid="8138799623850614177">"حذف کریں"</string>
<string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" منتخب کریں"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"داخلی اسٹوریج دکھائیں"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD کارڈ دکھائیں"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"داخلی اسٹوریج چھپائیں"</string>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index db35356..96241de 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Ulashish"</string>
<string name="menu_delete" msgid="8138799623850614177">"O‘chirish"</string>
<string name="menu_select" msgid="8711270657353563424">"“<xliff:g id="DIRECTORY">^1</xliff:g>” jildini tanlash"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ichki xotirani ko‘rsatish"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD kartani ko‘rsatish"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ichki xotirani berkitish"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index e4bbfda..581e2c9 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Chia sẻ"</string>
<string name="menu_delete" msgid="8138799623850614177">"Xóa"</string>
<string name="menu_select" msgid="8711270657353563424">"Chọn \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Hiển thị bộ nhớ trong"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Hiển thị thẻ SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ẩn bộ nhớ trong"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 4a44250..1b81ba4 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"分享"</string>
<string name="menu_delete" msgid="8138799623850614177">"删除"</string>
<string name="menu_select" msgid="8711270657353563424">"选择“<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"显示内部存储设备"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"显示SD卡"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"隐藏内部存储设备"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index e245c12..19460c1 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"分享"</string>
<string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
<string name="menu_select" msgid="8711270657353563424">"選取「<xliff:g id="DIRECTORY">^1</xliff:g>」"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"顯示內部儲存空間"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"顯示 SD 卡"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"隱藏內部儲存空間"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 464a13e..ca844c4 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"共用"</string>
<string name="menu_delete" msgid="8138799623850614177">"刪除"</string>
<string name="menu_select" msgid="8711270657353563424">"選取「<xliff:g id="DIRECTORY">^1</xliff:g>」"</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"顯示內部儲存空間"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"顯示 SD 卡"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"隱藏內部儲存空間"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index b35da3c..d21f07e 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -30,6 +30,8 @@
<string name="menu_share" msgid="3075149983979628146">"Yabelana"</string>
<string name="menu_delete" msgid="8138799623850614177">"Susa"</string>
<string name="menu_select" msgid="8711270657353563424">"Khetha i-\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+ <!-- no translation found for menu_select_all (4320518282375109902) -->
+ <skip />
<string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Bonisa isitoreji sangaphakathi"</string>
<string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Bonisa ikhadi le-SD"</string>
<string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Fihla isitoreji sangaphakathi"</string>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 268ce18..4ad337d 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -46,6 +46,8 @@
<string name="menu_delete">Delete</string>
<!-- Menu item title that selects the current directory [CHAR LIMIT=48] -->
<string name="menu_select">Select \"<xliff:g id="directory" example="My Directory">^1</xliff:g>\"</string>
+ <!-- Menu item title that selects all documents in the current directory [CHAR LIMIT=24] -->
+ <string name="menu_select_all">Select All</string>
<!-- Menu item that reveals internal storage built into the device [CHAR LIMIT=24] -->
<string name="menu_advanced_show" product="nosdcard">Show internal storage</string>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index f55912c..a75dc42 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -501,6 +501,14 @@
mode.finish();
return true;
+ } else if (id == R.id.menu_select_all) {
+ int count = mCurrentView.getCount();
+ for (int i = 0; i < count; i++) {
+ mCurrentView.setItemChecked(i, true);
+ }
+ updateDisplayState();
+ return true;
+
} else {
return false;
}
diff --git a/packages/IntentFilterVerifier/Android.mk b/packages/IntentFilterVerifier/Android.mk
new file mode 100644
index 0000000..99feda5
--- /dev/null
+++ b/packages/IntentFilterVerifier/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH:= $(call my-dir)
+
+# Build the IntentFilterVerifier.
+include $(CLEAR_VARS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ volley \
+
+LOCAL_JAVA_LIBRARIES += org.apache.http.legacy
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := IntentFilterVerifier
+
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_PROGUARD_FLAGS := $(proguard.flags)
+
+include $(BUILD_PACKAGE)
+
+# Build the test package.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/IntentFilterVerifier/AndroidManifest.xml b/packages/IntentFilterVerifier/AndroidManifest.xml
new file mode 100644
index 0000000..3829cc5
--- /dev/null
+++ b/packages/IntentFilterVerifier/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.verifier.intentfilter"
+ coreApp="true">
+ <uses-permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+
+ <application
+ android:label="@string/service_name"
+ android:allowBackup="false">
+
+ <receiver
+ android:name="com.android.verifier.intentfilter.IntentVerificationReceiver"
+ android:permission="android.permission.BIND_INTENT_FILTER_VERIFIER" >
+ <intent-filter
+ android:priority="-1" >
+ <action android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION" />
+ <data android:mimeType="application/vnd.android.package-archive" />
+ </intent-filter>
+ </receiver>
+
+ <service android:name=".IntentVerificationService"
+ android:label="@string/service_name"
+ android:exported="false"/>
+
+ </application>
+
+</manifest>
diff --git a/packages/IntentFilterVerifier/CleanSpec.mk b/packages/IntentFilterVerifier/CleanSpec.mk
new file mode 100644
index 0000000..e4575ae
--- /dev/null
+++ b/packages/IntentFilterVerifier/CleanSpec.mk
@@ -0,0 +1,49 @@
+# 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/packages/IntentFilterVerifier/proguard.flags b/packages/IntentFilterVerifier/proguard.flags
new file mode 100644
index 0000000..6e4bec3
--- /dev/null
+++ b/packages/IntentFilterVerifier/proguard.flags
@@ -0,0 +1 @@
+-verbose
\ No newline at end of file
diff --git a/packages/IntentFilterVerifier/res/values/strings.xml b/packages/IntentFilterVerifier/res/values/strings.xml
new file mode 100644
index 0000000..22f3cd5
--- /dev/null
+++ b/packages/IntentFilterVerifier/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Package name shown to users when they look at installed applications
+ and running processes. This service verifies packages that are
+ requested to be installed. [CHAR LIMIT=50] -->
+ <string name="service_name">Basic Intent Filter Verification Service</string>
+
+</resources>
diff --git a/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationReceiver.java b/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationReceiver.java
new file mode 100644
index 0000000..de25f8c
--- /dev/null
+++ b/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationReceiver.java
@@ -0,0 +1,90 @@
+/*
+ * 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.verifier.intentfilter;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class IntentVerificationReceiver extends BroadcastReceiver {
+ static final String TAG = IntentVerificationReceiver.class.getName();
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION.equals(action)) {
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ int verificationId = extras.getInt(
+ PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID);
+ String hosts = extras.getString(
+ PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS);
+
+ Log.d(TAG, "Received IntentFilter verification broadcast with verificationId: "
+ + verificationId);
+
+ if (canDoVerification(context)) {
+ Intent serviceIntent = new Intent(context, IntentVerificationService.class);
+ serviceIntent.fillIn(intent, 0);
+ serviceIntent.putExtras(intent.getExtras());
+
+ Slog.d(TAG, "Starting Intent Verification Service.");
+
+ context.startService(serviceIntent);
+ } else {
+ sendVerificationFailure(context, verificationId, hosts);
+ }
+ }
+
+ } else {
+ Log.w(TAG, "Unexpected action: " + action);
+ }
+ }
+
+ private void sendVerificationFailure(Context context, int verificationId, String hosts) {
+ List<String> list = Arrays.asList(hosts.split(" "));
+ context.getPackageManager().verifyIntentFilter(
+ verificationId, PackageManager.INTENT_FILTER_VERIFICATION_FAILURE, list);
+
+ Log.d(TAG, "No network! Failing IntentFilter verification with verificationId: " +
+ verificationId + " and hosts: " + hosts);
+ }
+
+ private boolean canDoVerification(Context context) {
+ return hasNetwork(context);
+ }
+
+ public boolean hasNetwork(Context context) {
+ ConnectivityManager cm =
+ (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (cm != null) {
+ NetworkInfo info = cm.getActiveNetworkInfo();
+ return (info != null) && info.isConnected();
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationRequest.java b/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationRequest.java
new file mode 100644
index 0000000..8f9c86f
--- /dev/null
+++ b/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationRequest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.verifier.intentfilter;
+
+import com.android.volley.Response;
+import com.android.volley.toolbox.JsonArrayRequest;
+import org.json.JSONArray;
+
+public class IntentVerificationRequest extends JsonArrayRequest {
+
+ public IntentVerificationRequest(String url, Response.Listener<JSONArray> listener,
+ Response.ErrorListener errorListener) {
+ super(url, listener, errorListener);
+ }
+}
diff --git a/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationService.java b/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationService.java
new file mode 100644
index 0000000..3e4db6c
--- /dev/null
+++ b/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationService.java
@@ -0,0 +1,468 @@
+/*
+ * 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.verifier.intentfilter;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import com.android.volley.RequestQueue;
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+import com.android.volley.toolbox.Volley;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+public class IntentVerificationService extends Service {
+ private static final String TAG = "IntentVerificationService";
+
+ private static final String WELL_KNOWN_ASSOCIATIONS_JSON = "/.well-known/associations.json";
+ private static final String DEFAULT_SCHEME = "https";
+
+ private static final String JSON_KEY_TARGET = "target";
+ private static final String JSON_KEY_NAMESPACE = "namespace";
+ private static final String JSON_KEY_PACKAGE_NAME = "package_name";
+ private static final String JSON_KEY_CERT_FINGERPRINTS = "sha256_cert_fingerprints";
+
+ private static final String JSON_VAL_ANDROID_APP = "android_app";
+
+ private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ private ConnectivityManager mConnectivityManager;
+ private Looper mHandlerLooper;
+ private VerificationHandler mHandler;
+ private RequestQueue mRequestQueue;
+
+ private static class VerificationState {
+ public final int verificationId;
+ public final String hosts;
+ public final String packageName;
+ public final Set<String> fingerprints;
+ public int responseCode = PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS;
+ public int counter;
+ public int numberOfHosts;
+ public ArrayList<String> failedHosts = new ArrayList<>();
+
+ private final Object lock = new Object();
+
+ public VerificationState(int id, String h, String p, Set<String> fps) {
+ verificationId = id;
+ hosts = h;
+ packageName = p;
+ fingerprints = fps;
+ numberOfHosts = hosts.split(" ").length;
+ }
+ public boolean setResponseCodeAndCheckMax(int code) {
+ synchronized (lock) {
+ if (code == PackageManager.INTENT_FILTER_VERIFICATION_FAILURE) {
+ responseCode = code;
+ counter++;
+ } else if (code == PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS) {
+ counter++;
+ }
+ return (counter == numberOfHosts);
+ }
+ }
+
+ public void addFailedHost(String host) {
+ synchronized (failedHosts) {
+ failedHosts.add(host);
+ }
+ }
+
+ public ArrayList<String> getFailedHosts() {
+ return failedHosts;
+ }
+ }
+
+ private HashMap<Integer, VerificationState> mVerificationMap =
+ new HashMap<Integer, VerificationState>();
+
+ private class VerificationHandler extends Handler {
+ private static final int MSG_STOP_SERVICE = 0;
+ private static final int MSG_VERIFY_INTENT_START = 1;
+ private static final int MSG_VERIFY_INTENT_DONE = 2;
+
+ private static final long SHUTDOWN_DELAY_MILLIS = 8 * 1000;
+
+ private final Context mContext;
+
+ public VerificationHandler(Context context, Looper looper) {
+ super(looper);
+
+ mContext = context;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_VERIFY_INTENT_START:
+ final Intent intent = (Intent) msg.obj;
+ Bundle extras = intent.getExtras();
+ boolean immediate = false;
+
+ if (extras != null) {
+ immediate = doVerification(extras);
+ }
+
+ // There was no network, so we can stop soon
+ if (immediate) {
+ stopDelayed();
+ }
+ break;
+
+ case MSG_VERIFY_INTENT_DONE:
+ VerificationState vs = (VerificationState) msg.obj;
+ processVerificationDone(mContext, vs);
+ clearVerificationState(vs);
+ break;
+
+ case MSG_STOP_SERVICE:
+ stopSelf();
+ break;
+
+ default:
+ Slog.i(TAG, "Unknown message posted " + msg.toString());
+ break;
+
+ }
+ }
+
+ private void stopDelayed() {
+ removeMessages(MSG_STOP_SERVICE);
+ sendEmptyMessageDelayed(MSG_STOP_SERVICE, SHUTDOWN_DELAY_MILLIS);
+ }
+ }
+
+ private VerificationState getVerificationState(int id, String hosts, String packageName,
+ Set<String> fingerprints) {
+ synchronized (mVerificationMap) {
+ VerificationState vs = mVerificationMap.get(id);
+ if (vs == null) {
+ vs = new VerificationState(id, hosts, packageName, fingerprints);
+ }
+ return vs;
+ }
+ }
+
+ private void clearVerificationState(VerificationState vs) {
+ mVerificationMap.remove(vs);
+ }
+
+ private boolean doVerification(Bundle extras) {
+ String scheme = extras.getString(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME);
+ if (TextUtils.isEmpty(scheme)) {
+ scheme = DEFAULT_SCHEME;
+ }
+
+ int verificationId = extras.getInt(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID);
+ String hosts = extras.getString(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS);
+ String packageName = extras.getString(
+ PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME);
+
+ Set<String> fingerprints = getFingerprints(packageName);
+
+ Log.d(TAG, "Received IntentFilter verification broadcast with verificationId:" +
+ verificationId + " hosts:'" + hosts + "' scheme:" + scheme);
+
+ VerificationState vs = getVerificationState(verificationId, hosts, packageName,
+ fingerprints);
+
+ if (hasNetwork()) {
+ sendNetworkVerifications(scheme, vs);
+ return false;
+ }
+
+ // No network, so fail immediately
+ sendFailureResponseIfNeeded(vs);
+
+ return true;
+ }
+
+ private Set<String> getFingerprints(String packageName) {
+ Context context = getApplicationContext();
+ try {
+ Signature[] signatures = context.getPackageManager().getPackageInfo(packageName,
+ PackageManager.GET_SIGNATURES).signatures;
+ if (signatures.length > 0) {
+ HashSet<String> result = new HashSet<String>();
+ for (Signature sig : signatures) {
+ String fingerprint = computeNormalizedSha256Fingerprint(sig.toByteArray());
+ result.add(fingerprint);
+ }
+ return result;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Cannot get signatures for package name: " + packageName);
+ }
+ return Collections.EMPTY_SET;
+ }
+
+ private static String computeNormalizedSha256Fingerprint(byte[] signature) {
+ MessageDigest digester;
+ try {
+ digester = MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError("No SHA-256 implementation found.");
+ }
+ digester.update(signature);
+ return byteArrayToHexString(digester.digest());
+ }
+
+ private static String byteArrayToHexString(byte[] array) {
+ if (array.length == 0) {
+ return "";
+ }
+ char[] buf = new char[array.length * 3 - 1];
+
+ int bufIndex = 0;
+ for (int i = 0; i < array.length; i++) {
+ byte b = array[i];
+ if (i > 0) {
+ buf[bufIndex++] = ':';
+ }
+ buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
+ buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
+ }
+ return new String(buf);
+ }
+
+ private static String getAssociationPath() {
+ return WELL_KNOWN_ASSOCIATIONS_JSON;
+ }
+
+ private void sendNetworkVerifications(String scheme, final VerificationState vs) {
+ final int verificationId = vs.verificationId;
+ final String hosts = vs.hosts;
+
+ String[] array = hosts.split(" ");
+ for (final String host : array) {
+ try {
+ final URL url = new URL(scheme, host, getAssociationPath());
+ final String urlStr = url.toString();
+ Log.d(TAG, "Using verification URL: " + urlStr);
+ IntentVerificationRequest req = new IntentVerificationRequest(urlStr,
+ new Response.Listener<JSONArray>() {
+ @Override
+ public void onResponse(JSONArray response) {
+ Log.d(TAG, "From: " + urlStr + " received response: "
+ + response.toString());
+ handleResponse(vs, host, response);
+ }
+ }, new Response.ErrorListener() {
+ @Override
+ public void onErrorResponse(VolleyError error) {
+ Slog.d(TAG, "From: " + urlStr + " got error: " + error.getMessage()
+ + (error.networkResponse != null ? " with status code: "
+ + error.networkResponse.statusCode : ""));
+ handleError(vs, host);
+ }
+ }
+ );
+ mRequestQueue.add(req);
+ } catch (MalformedURLException e) {
+ Log.w(TAG, "Cannot send verificationId: " + verificationId + " to host: " + host);
+ }
+ }
+ }
+
+ private void handleError(VerificationState vs, String host) {
+ vs.addFailedHost(host);
+ sendFailureResponseIfNeeded(vs);
+ }
+
+ private void handleResponse(VerificationState vs, String host, JSONArray response) {
+ try {
+ if (response.length() == 0) {
+ Log.d(TAG, "Domain response is empty!");
+ handleError(vs, host);
+ return;
+ }
+
+ JSONObject firstRelation = (JSONObject) response.get(0);
+ if (firstRelation == null) {
+ Log.d(TAG, "Domain response is should have a relation!");
+ handleError(vs, host);
+ return;
+ }
+
+ JSONObject target = (JSONObject) firstRelation.get(JSON_KEY_TARGET);
+ if (target == null) {
+ Log.d(TAG, "Domain response target is empty!");
+ handleError(vs, host);
+ return;
+ }
+
+ String nameSpace = target.getString(JSON_KEY_NAMESPACE);
+ if (TextUtils.isEmpty(nameSpace) || !nameSpace.equals(JSON_VAL_ANDROID_APP)) {
+ Log.d(TAG, "Domain response target name space is not valid: " + nameSpace);
+ handleError(vs, host);
+ return;
+ }
+
+ String packageName = target.getString(JSON_KEY_PACKAGE_NAME);
+ JSONArray certFingerprints = target.getJSONArray(JSON_KEY_CERT_FINGERPRINTS);
+
+ // Early exits is the JSON response is not correct for the package name or signature
+ if (TextUtils.isEmpty(packageName)) {
+ Log.d(TAG, "Domain response has empty package name!");
+ handleError(vs, host);
+ return;
+ }
+ if (certFingerprints.length() == 0) {
+ Log.d(TAG, "Domain response has empty cert signature!");
+ handleError(vs, host);
+ return;
+ }
+ // Now do the real test on package name and signature
+ if (!packageName.equalsIgnoreCase(vs.packageName)) {
+ Log.d(TAG, "Domain response has package name mismatch!" + packageName +
+ " vs " + vs.packageName);
+ handleError(vs, host);
+ return;
+ }
+ final int count = certFingerprints.length();
+ for (int i = 0; i < count; i++) {
+ String fingerprint = certFingerprints.getString(i);
+ if (!vs.fingerprints.contains(fingerprint)) {
+ Log.d(TAG, "Domain response has cert fingerprint mismatch! " +
+ "The domain fingerprint '" + fingerprint + "' is not from the App");
+ handleError(vs, host);
+ return;
+ }
+ }
+ sendSuccessResponseIfNeeded(vs);
+ } catch (JSONException e) {
+ Log.d(TAG, "Domain response is not well formed", e);
+ handleError(vs, host);
+ }
+ }
+
+ private void sendSuccessResponseIfNeeded(VerificationState vs) {
+ if (vs.setResponseCodeAndCheckMax(PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS)) {
+ sendMessage(vs);
+ }
+ }
+
+ private void sendFailureResponseIfNeeded(VerificationState vs) {
+ if (vs.setResponseCodeAndCheckMax(PackageManager.INTENT_FILTER_VERIFICATION_FAILURE)) {
+ sendMessage(vs);
+ }
+ }
+
+ private void sendMessage(VerificationState vs) {
+ Message msg = mHandler.obtainMessage(VerificationHandler.MSG_VERIFY_INTENT_DONE);
+ msg.obj = vs;
+ mHandler.sendMessage(msg);
+ }
+
+ private void processVerificationDone(Context context, VerificationState state) {
+ int verificationId = state.verificationId;
+ String hosts = state.hosts;
+ int responseCode = state.responseCode;
+
+ final PackageManager pm = context.getPackageManager();
+
+ // Callback the PackageManager
+ pm.verifyIntentFilter(verificationId, responseCode, state.getFailedHosts());
+ Log.d(TAG, "IntentFilter with verificationId: " + verificationId + " and hosts: " +
+ hosts + " got verification code: " + responseCode);
+ }
+
+ /**
+ * We only connect to this service from the same process.
+ */
+ public class LocalBinder extends Binder {
+ IntentVerificationService getService() { return IntentVerificationService.this; }
+ }
+
+ private final IBinder mBinder = new LocalBinder();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Slog.i(TAG, "Received start id " + startId + ": " + intent);
+
+ final Message msg = mHandler.obtainMessage(VerificationHandler.MSG_VERIFY_INTENT_START);
+ msg.obj = intent;
+ mHandler.sendMessage(msg);
+
+ return START_STICKY;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ Slog.d(TAG, "Starting up...");
+
+ final HandlerThread handlerThread = new HandlerThread("IntentVerificationService");
+ handlerThread.start();
+ mHandlerLooper = handlerThread.getLooper();
+
+ mHandler = new VerificationHandler(getApplicationContext(), mHandlerLooper);
+
+ mRequestQueue = Volley.newRequestQueue(this);
+ mRequestQueue.start();
+
+ mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ Slog.d(TAG, "Shutting down...");
+
+ mHandlerLooper.quit();
+ mRequestQueue.stop();
+ }
+
+ private boolean hasNetwork() {
+ NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
+ return (info != null) && info.isConnected();
+ }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
index 3627e3e..7d5bf6b 100644
--- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java
@@ -36,7 +36,10 @@
* allows the user to return to the call.
*/
public class EmergencyButton extends Button {
- private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+ private static final Intent INTENT_EMERGENCY_DIAL = new Intent()
+ .setAction("com.android.phone.EmergencyDialer.DIAL")
+ .setPackage("com.android.phone")
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -112,12 +115,9 @@
mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall();
}
} else {
- final boolean bypassHandler = true;
- KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(bypassHandler);
- Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- getContext().startActivityAsUser(intent,
+ KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction(
+ true /* bypassHandler */);
+ getContext().startActivityAsUser(INTENT_EMERGENCY_DIAL,
new UserHandle(mLockPatternUtils.getCurrentUser()));
}
}
diff --git a/packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
similarity index 84%
rename from packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml
rename to packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
index 29e4bce..26c9b1a 100644
--- a/packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
@@ -41,20 +41,6 @@
android:layout_margin="10dp"
android:background="@drawable/vector_drawable_place_right" />
<Button
- android:id="@+id/place_top"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_top" />
- <Button
- android:id="@+id/place_bottom"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_bottom" />
- <Button
android:id="@+id/place_top_left"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
similarity index 84%
copy from packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml
copy to packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
index 29e4bce..e180daa 100644
--- a/packages/SystemUI/res/layout-sw600dp/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
@@ -27,20 +27,6 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
- android:id="@+id/place_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_left" />
- <Button
- android:id="@+id/place_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_right" />
- <Button
android:id="@+id/place_top"
android:layout_width="36dp"
android:layout_height="36dp"
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 884272d..9fe24f4 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -370,8 +370,8 @@
<string name="notification_collapse_button_text" msgid="6883253262134328057">"모두 숨기기"</string>
<string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="screen_pinning_title" msgid="3273740381976175811">"화면 고정됨"</string>
- <string name="screen_pinning_description" msgid="1346522416878235405">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 뒤로와 개요를 동시에 길게 터치합니다."</string>
- <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 개요를 길게 터치합니다."</string>
+ <string name="screen_pinning_description" msgid="1346522416878235405">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 뒤로와 최근 사용을 동시에 길게 터치합니다."</string>
+ <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 최근 사용을 길게 터치합니다."</string>
<string name="screen_pinning_positive" msgid="3783985798366751226">"확인"</string>
<string name="screen_pinning_negative" msgid="3741602308343880268">"거부"</string>
<string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index e81a1d0..3a97a41 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -815,7 +815,9 @@
}
// Start dozing
- mUIDozeTrigger.startDozing();
+ if (!mConfig.multiStackEnabled) {
+ mUIDozeTrigger.startDozing();
+ }
}
/** Requests this task stacks to start it's enter-recents animation */
@@ -1219,7 +1221,7 @@
RecentsTaskLoader.getInstance().loadTaskData(task);
// If the doze trigger has already fired, then update the state for this task view
- if (mUIDozeTrigger.hasTriggered()) {
+ if (mConfig.multiStackEnabled || mUIDozeTrigger.hasTriggered()) {
tv.setNoUserInteractionState();
}
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index c4daaa9..2b2e611 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -273,8 +273,8 @@
}
/**
- * @hide
* Enable/Disable AutoPadding for Vec3 elements.
+ * By default: Diabled.
*
* @param useAutoPadding True: enable AutoPadding; flase: disable AutoPadding
*
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index 60ff996..4b3e30f 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -119,9 +119,6 @@
*/
public enum DataType {
NONE (0, 0),
- /**
- * @hide
- */
FLOAT_16 (1, 2),
FLOAT_32 (2, 4),
FLOAT_64 (3, 8),
@@ -390,9 +387,6 @@
return rs.mElement_I64;
}
- /**
- * @hide
- */
public static Element F16(RenderScript rs) {
if(rs.mElement_F16 == null) {
rs.mElement_F16 = createUser(rs, DataType.FLOAT_16);
@@ -534,9 +528,6 @@
return rs.mElement_RGBA_8888;
}
- /**
- * @hide
- */
public static Element F16_2(RenderScript rs) {
if(rs.mElement_HALF_2 == null) {
rs.mElement_HALF_2 = createVector(rs, DataType.FLOAT_16, 2);
@@ -544,9 +535,6 @@
return rs.mElement_HALF_2;
}
- /**
- * @hide
- */
public static Element F16_3(RenderScript rs) {
if(rs.mElement_FLOAT_3 == null) {
rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_16, 3);
@@ -554,9 +542,6 @@
return rs.mElement_HALF_3;
}
- /**
- * @hide
- */
public static Element F16_4(RenderScript rs) {
if(rs.mElement_HALF_4 == null) {
rs.mElement_HALF_4 = createVector(rs, DataType.FLOAT_16, 4);
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index e8e942c..7ef17a7 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -139,7 +139,8 @@
* Returns an identifier that can be used to identify a particular
* minor version of RS.
*
- * @hide
+ * @return The minor RenderScript version number
+ *
*/
public static long getMinorID() {
return sMinorID;
@@ -1321,7 +1322,6 @@
/**
* Create a RenderScript context.
*
- * @hide
* @param ctx The context.
* @return RenderScript
*/
@@ -1418,14 +1418,13 @@
/**
* Gets or creates a RenderScript context of the specified type.
*
- * @hide
* @param ctx The context.
* @param ct The type of context to be created.
* @param sdkVersion The target SDK Version.
* @param flags The OR of the CREATE_FLAG_* options desired
* @return RenderScript
*/
- public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, int flags) {
+ private static RenderScript create(Context ctx, int sdkVersion, ContextType ct, int flags) {
if (sdkVersion < 23) {
return internalCreate(ctx, sdkVersion, ct, flags);
}
@@ -1448,8 +1447,6 @@
}
/**
- * @hide
- *
* Releases all the process contexts. This is the same as
* calling .destroy() on each unique context retreived with
* create(...). If no contexts have been created this
@@ -1486,7 +1483,6 @@
*
* If you need a single context please use create()
*
- * @hide
* @param ctx The context.
* @return RenderScript
*/
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index 65056ac..6a1efee 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -66,7 +66,6 @@
}
/**
- * @hide Pending API review
* InvokeID is an identifier for an invoke function. It is used
* as an identifier for ScriptGroup creation.
*
@@ -86,7 +85,6 @@
private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>();
/**
- * @hide Pending API review
* Only to be used by generated reflected classes.
*/
protected InvokeID createInvokeID(int slot) {
@@ -222,22 +220,21 @@
/**
* Only intended for use by generated reflected code.
- *
- * @hide
*/
protected void forEach(int slot, Allocation[] ains, Allocation aout,
FieldPacker v) {
+
+ // FieldPacker is kept here to support regular params in the future.
forEach(slot, ains, aout, v, null);
}
/**
* Only intended for use by generated reflected code.
- *
- * @hide
*/
protected void forEach(int slot, Allocation[] ains, Allocation aout,
FieldPacker v, LaunchOptions sc) {
// TODO: Is this necessary if nScriptForEach calls validate as well?
+ // FieldPacker is kept here to support regular params in the future.
mRS.validate();
if (ains != null) {
for (Allocation ain : ains) {
@@ -476,7 +473,23 @@
/**
- * Class used to specify clipping for a kernel launch.
+ * Class for specifying the specifics about how a kernel will be
+ * launched
+ *
+ * This class can specify a potential range of cells on which to
+ * run a kernel. If no set is called for a dimension then this
+ * class will have no impact on that dimension when the kernel
+ * is executed.
+ *
+ * The forEach launch will operate over the intersection of the
+ * dimensions.
+ *
+ * Example:
+ * LaunchOptions with setX(5, 15)
+ * Allocation with dimension X=10, Y=10
+ * The resulting forEach run would execute over x = 5 to 10 and
+ * y = 0 to 10.
+ *
*
*/
public static final class LaunchOptions {
diff --git a/rs/java/android/renderscript/ScriptGroup2.java b/rs/java/android/renderscript/ScriptGroup2.java
index 4a56572..9d73ac4 100644
--- a/rs/java/android/renderscript/ScriptGroup2.java
+++ b/rs/java/android/renderscript/ScriptGroup2.java
@@ -24,26 +24,41 @@
import java.util.Map;
/**
+ * ScriptGroup2 is a new, enhanced API for script groups.
+ * A script group is a collection of kernels or invocable functions, with
+ * data dependencies defined among them. A script group is launched for
+ * execution as a whole, rather than launching each kernel or invocable function
+ * separately. Once created, a script group can be repeatedly used with
+ * different inputs.
+ * <p>
+ * In the new ScriptGroup2 API, a script group is modeled using closures.
+ * A closure, in this context, is defined as a function call to a kernel or
+ * invocable function. Each function argument or global variable accessed inside
+ * the function is bound to 1) a known value, 2) a script group input, or 3) a
+ * future. A future is the output of a closure, i.e., the return value of the
+ * function or a global variable written by that function.
+ * <p>
+ * A script group is a directed acyclic graph (DAG), in which closures are the
+ * vertices and the dependencies among them are the edges.
+ * The way the ScriptGroup2 API is designed makes cycles impossible in a script
+ * group. For example, it is impossible to make forward references to futures,
+ * i.e., it is impossible to set as input to a closure the future from itself or
+ * a future from another closure that directly or indirectly depends on it.
+ * <p>
+ * Grouping kernels and invocable functions together allows to execute them more
+ * efficiently. Runtime and compiler optimizations are applied to script
+ * groups, to reduce computation or communication overhead, and to make more
+ * efficient use of the CPU and the GPU.
+ */
-******************************
-You have tried to change the API from what has been previously approved.
-
-To make these errors go away, you have two choices:
-1) You can add "@hide" javadoc comments to the methods, etc. listed in the
-errors above.
-
-2) You can update current.txt by executing the following command:
-make update-api
-
-To submit the revised current.txt to the main Android repository,
-you will need approval.
-******************************
-
-@hide Pending Android public API approval.
-*/
public class ScriptGroup2 extends BaseObj {
+ /**
+ * An opaque class for closures
+ */
+
public static class Closure extends BaseObj {
+ private Object[] mArgs;
private Allocation mReturnValue;
private Map<Script.FieldID, Object> mBindings;
@@ -62,8 +77,9 @@
Object[] args, Map<Script.FieldID, Object> globals) {
super(0, rs);
+ mArgs = args;
mReturnValue = Allocation.createTyped(rs, returnType);
- mBindings = new HashMap<Script.FieldID, Object>();
+ mBindings = globals;
mGlobalFuture = new HashMap<Script.FieldID, Future>();
int numValues = args.length + globals.size();
@@ -112,7 +128,8 @@
super(0, rs);
mFP = FieldPacker.createFieldPack(args);
- mBindings = new HashMap<Script.FieldID, Object>();
+ mArgs = args;
+ mBindings = globals;
mGlobalFuture = new HashMap<Script.FieldID, Future>();
int numValues = globals.size();
@@ -132,7 +149,6 @@
UnboundValue unbound = (UnboundValue)obj;
unbound.addReference(this, fieldID);
} else {
- // TODO(yangni): Verify obj not a future.
retrieveValueAndDependenceInfo(rs, i, obj, values,
sizes, depClosures, depFieldIDs);
}
@@ -174,6 +190,12 @@
sizes[index] = vs.size;
}
+ /**
+ * Returns the future for the return value
+ *
+ * @return a future
+ */
+
public Future getReturn() {
if (mReturnFuture == null) {
mReturnFuture = new Future(this, null, mReturnValue);
@@ -182,6 +204,13 @@
return mReturnFuture;
}
+ /**
+ * Returns the future for a global variable
+ *
+ * @param field the field ID for the global variable
+ * @return a future
+ */
+
public Future getGlobal(Script.FieldID field) {
Future f = mGlobalFuture.get(field);
@@ -198,11 +227,13 @@
}
void setArg(int index, Object obj) {
+ mArgs[index] = obj;
ValueAndSize vs = new ValueAndSize(mRS, obj);
mRS.nClosureSetArg(getID(mRS), index, vs.value, vs.size);
}
void setGlobal(Script.FieldID fieldID, Object obj) {
+ mBindings.put(fieldID, obj);
ValueAndSize vs = new ValueAndSize(mRS, obj);
mRS.nClosureSetGlobal(getID(mRS), fieldID.getID(mRS), vs.value, vs.size);
}
@@ -234,6 +265,10 @@
}
}
+ /**
+ * An opaque class for futures
+ */
+
public static class Future {
Closure mClosure;
Script.FieldID mFieldID;
@@ -250,6 +285,10 @@
Object getValue() { return mValue; }
}
+ /**
+ * An opaque class for unbound values (a.k.a. script group inputs)
+ */
+
public static class UnboundValue {
// Either mFieldID or mArgIndex should be set but not both.
List<Pair<Closure, Script.FieldID>> mFieldID;
@@ -309,6 +348,13 @@
setID(id);
}
+ /**
+ * Executes a script group
+ *
+ * @param inputs inputs to the script group
+ * @return outputs of the script group as an array of objects
+ */
+
public Object[] execute(Object... inputs) {
if (inputs.length < mInputs.size()) {
Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
@@ -343,32 +389,95 @@
}
/**
- @hide Pending Android public API approval.
- */
+ * A class representing a binding of a value to a global variable in a
+ * kernel or invocable function. Such a binding can be used to create a
+ * closure.
+ */
+
public static final class Binding {
- public Script.FieldID mField;
- public Object mValue;
+ private Script.FieldID mField;
+ private Object mValue;
+
+ /**
+ * Returns a Binding object that binds value to field
+ *
+ * @param field the Script.FieldID of the global variable
+ * @param value the value
+ */
+
public Binding(Script.FieldID field, Object value) {
mField = field;
mValue = value;
}
+
+ /**
+ * Returns the field ID
+ */
+
+ public Script.FieldID getField() { return mField; }
+
+ /**
+ * Returns the value
+ */
+
+ public Object getValue() { return mValue; }
}
/**
- @hide Pending Android public API approval.
- */
+ * The builder class to create a script group.
+ * <p>
+ * Closures are created using the {@link #addKernel} or {@link #addInvoke}
+ * methods.
+ * When a closure is created, futures from previously created closures
+ * can be used as inputs.
+ * Unbound values can be used as inputs to create closures as well.
+ * An unbound value is created using the {@link #addInput} method.
+ * Unbound values become inputs to the script group to be created,
+ * in the order that they are added.
+ * A script group is created by a call to the {@link #create} method, which
+ * accepts an array of futures as the outputs for the script group.
+ * <p>
+ * Closures in a script group can be evaluated in any order as long as the
+ * following conditions are met.
+ * First, a closure must be evaluated before any other closures that take its
+ * futures as inputs.
+ * Second, all closures added before an invoke closure must be evaluated
+ * before it.
+ * Third, all closures added after an invoke closure must be evaluated after
+ * it.
+ * <p>
+ * As a special case, the order that the closures are added is a legal
+ * evaluation order. However, other evaluation orders are allowed, including
+ * concurrently evaluating independent closures.
+ */
+
public static final class Builder {
RenderScript mRS;
List<Closure> mClosures;
List<UnboundValue> mInputs;
private static final String TAG = "ScriptGroup2.Builder";
+ /**
+ * Returns a Builder object
+ *
+ * @param rs the RenderScript context
+ */
public Builder(RenderScript rs) {
mRS = rs;
mClosures = new ArrayList<Closure>();
mInputs = new ArrayList<UnboundValue>();
}
+ /**
+ * Adds a closure for a kernel
+ *
+ * @param k Kernel ID for the kernel function
+ * @param returnType Allocation type for the return value
+ * @param args arguments to the kernel function
+ * @param globalBindings bindings for global variables
+ * @return a closure
+ */
+
public Closure addKernel(Script.KernelID k, Type returnType, Object[] args,
Map<Script.FieldID, Object> globalBindings) {
Closure c = new Closure(mRS, k, returnType, args, globalBindings);
@@ -376,6 +485,15 @@
return c;
}
+ /**
+ * Adds a closure for an invocable function
+ *
+ * @param invoke Invoke ID for the invocable function
+ * @param args arguments to the invocable function
+ * @param globalBindings bindings for global variables
+ * @return a closure
+ */
+
public Closure addInvoke(Script.InvokeID invoke, Object[] args,
Map<Script.FieldID, Object> globalBindings) {
Closure c = new Closure(mRS, invoke, args, globalBindings);
@@ -383,12 +501,25 @@
return c;
}
+ /**
+ * Adds a script group input
+ *
+ * @return a unbound value that can be used to create a closure
+ */
public UnboundValue addInput() {
UnboundValue unbound = new UnboundValue();
mInputs.add(unbound);
return unbound;
}
+ /**
+ * Adds a closure for a kernel
+ *
+ * @param k Kernel ID for the kernel function
+ * @param argsAndBindings arguments followed by bindings for global variables
+ * @return a closure
+ */
+
public Closure addKernel(Script.KernelID k, Type returnType, Object... argsAndBindings) {
ArrayList<Object> args = new ArrayList<Object>();
Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
@@ -398,6 +529,14 @@
return addKernel(k, returnType, args.toArray(), bindingMap);
}
+ /**
+ * Adds a closure for an invocable function
+ *
+ * @param invoke Invoke ID for the invocable function
+ * @param argsAndBindings arguments followed by bindings for global variables
+ * @return a closure
+ */
+
public Closure addInvoke(Script.InvokeID invoke, Object... argsAndBindings) {
ArrayList<Object> args = new ArrayList<Object>();
Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
@@ -407,6 +546,13 @@
return addInvoke(invoke, args.toArray(), bindingMap);
}
+ /**
+ * Creates a script group
+ *
+ * @param outputs futures intended as outputs of the script group
+ * @return a script group
+ */
+
public ScriptGroup2 create(Future... outputs) {
ScriptGroup2 ret = new ScriptGroup2(mRS, mClosures, mInputs, outputs);
return ret;
@@ -428,7 +574,7 @@
return false;
}
Binding b = (Binding)argsAndBindings[i];
- bindingMap.put(b.mField, b.mValue);
+ bindingMap.put(b.getField(), b.getValue());
}
return true;
diff --git a/rs/java/android/renderscript/Type.java b/rs/java/android/renderscript/Type.java
index a58e42c..cc9b58b 100644
--- a/rs/java/android/renderscript/Type.java
+++ b/rs/java/android/renderscript/Type.java
@@ -150,24 +150,29 @@
}
/**
- * @hide
- */
- public int getArray(int dim) {
- if ((dim < 0) || (dim >= mMaxArrays)) {
+ * Return the dimension of the specified array.
+ *
+ * @param arrayNum The array dimension to query
+ * @return int
+ */
+ public int getArray(int arrayNum) {
+ if ((arrayNum < 0) || (arrayNum >= mMaxArrays)) {
throw new RSIllegalArgumentException("Array dimension out of range.");
}
- if (mArrays == null || dim >= mArrays.length) {
+ if (mArrays == null || arrayNum >= mArrays.length) {
// Dimension in range but no array for that dimension allocated
return 0;
}
- return mArrays[dim];
+ return mArrays[arrayNum];
}
/**
- * @hide
- */
+ * Return the number of array dimensions.
+ *
+ * @return int
+ */
public int getArrayCount() {
if (mArrays != null) return mArrays.length;
return 0;
@@ -377,7 +382,7 @@
}
/**
- * @hide
+ * Adds an array dimension to the builder
*
* @param dim
* @param value
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 886845c..40fad38 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -367,7 +367,7 @@
return (jlong)(uintptr_t)rsClosureCreate(
(RsContext)con, (RsScriptKernelID)kernelID, (RsAllocation)returnValue,
fieldIDs, (size_t)fieldIDs_length, values, (size_t)values_length,
- (size_t*)sizes, (size_t)sizes_length,
+ (int*)sizes, (size_t)sizes_length,
depClosures, (size_t)depClosures_length,
depFieldIDs, (size_t)depFieldIDs_length);
}
@@ -400,7 +400,7 @@
return (jlong)(uintptr_t)rsInvokeClosureCreate(
(RsContext)con, (RsScriptInvokeID)invokeID, jParams, jParamLength,
fieldIDs, (size_t)fieldIDs_length, values, (size_t)values_length,
- (size_t*)sizes, (size_t)sizes_length);
+ (int*)sizes, (size_t)sizes_length);
}
static void
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 45b0fb2..5cc59e5 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3938,16 +3938,6 @@
return;
}
- // Don't proceed unless we have already established package metadata
- // for the current dataset via a key/value backup pass.
- File stateDir = new File(mBaseStateDir, transport.transportDirName());
- File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL);
- if (pmState.length() <= 0) {
- Slog.i(TAG, "Full backup requested but dataset not yet initialized "
- + "via k/v backup pass; ignoring");
- return;
- }
-
// Set up to send data to the transport
final int N = mPackages.size();
for (int i = 0; i < N; i++) {
@@ -4296,6 +4286,31 @@
writeFullBackupScheduleAsync();
}
+ private boolean fullBackupAllowable(IBackupTransport transport) {
+ if (transport == null) {
+ Slog.w(TAG, "Transport not present; full data backup not performed");
+ return false;
+ }
+
+ // Don't proceed unless we have already established package metadata
+ // for the current dataset via a key/value backup pass.
+ try {
+ File stateDir = new File(mBaseStateDir, transport.transportDirName());
+ File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL);
+ if (pmState.length() <= 0) {
+ if (DEBUG) {
+ Slog.i(TAG, "Full backup requested but dataset not yet initialized");
+ }
+ return false;
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Unable to contact transport");
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Conditions are right for a full backup operation, so run one. The model we use is
* to perform one app backup per scheduled job execution, and to reschedule the job
@@ -4307,6 +4322,7 @@
boolean beginFullBackup(FullBackupJob scheduledJob) {
long now = System.currentTimeMillis();
FullBackupEntry entry = null;
+ long latency = MIN_FULL_BACKUP_INTERVAL;
if (!mEnabled || !mProvisioned) {
// Backups are globally disabled, so don't proceed. We also don't reschedule
@@ -4338,17 +4354,41 @@
return false;
}
- entry = mFullBackupQueue.get(0);
- long timeSinceRun = now - entry.lastBackup;
- if (timeSinceRun < MIN_FULL_BACKUP_INTERVAL) {
- // It's too early to back up the next thing in the queue, so bow out
+ // At this point we know that we have work to do, just not right now. Any
+ // exit without actually running backups will also require that we
+ // reschedule the job.
+ boolean runBackup = true;
+
+ if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
if (MORE_DEBUG) {
- Slog.i(TAG, "Device ready but too early to back up next app");
+ Slog.i(TAG, "Preconditions not met; not running full backup");
}
- final long latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
+ runBackup = false;
+ // Typically this means we haven't run a key/value backup yet. Back off
+ // full-backup operations by the key/value job's run interval so that
+ // next time we run, we are likely to be able to make progress.
+ latency = KeyValueBackupJob.BATCH_INTERVAL;
+ }
+
+ if (runBackup) {
+ entry = mFullBackupQueue.get(0);
+ long timeSinceRun = now - entry.lastBackup;
+ runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL);
+ if (!runBackup) {
+ // It's too early to back up the next thing in the queue, so bow out
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Device ready but too early to back up next app");
+ }
+ // Wait until the next app in the queue falls due for a full data backup
+ latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun;
+ }
+ }
+
+ if (!runBackup) {
+ final long deferTime = latency; // pin for the closure
mBackupHandler.post(new Runnable() {
@Override public void run() {
- FullBackupJob.schedule(mContext, latency);
+ FullBackupJob.schedule(mContext, deferTime);
}
});
return false;
@@ -8489,27 +8529,31 @@
throw new IllegalStateException("Restore supported only for the device owner");
}
- if (DEBUG) {
- Slog.d(TAG, "fullTransportBackup()");
- }
-
- CountDownLatch latch = new CountDownLatch(1);
- PerformFullTransportBackupTask task =
- new PerformFullTransportBackupTask(null, pkgNames, false, null, latch);
- (new Thread(task, "full-transport-master")).start();
- do {
- try {
- latch.await();
- break;
- } catch (InterruptedException e) {
- // Just go back to waiting for the latch to indicate completion
+ if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
+ Slog.i(TAG, "Full backup not currently possible -- key/value backup not yet run?");
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "fullTransportBackup()");
}
- } while (true);
- // We just ran a backup on these packages, so kick them to the end of the queue
- final long now = System.currentTimeMillis();
- for (String pkg : pkgNames) {
- enqueueFullBackup(pkg, now);
+ CountDownLatch latch = new CountDownLatch(1);
+ PerformFullTransportBackupTask task =
+ new PerformFullTransportBackupTask(null, pkgNames, false, null, latch);
+ (new Thread(task, "full-transport-master")).start();
+ do {
+ try {
+ latch.await();
+ break;
+ } catch (InterruptedException e) {
+ // Just go back to waiting for the latch to indicate completion
+ }
+ } while (true);
+
+ // We just ran a backup on these packages, so kick them to the end of the queue
+ final long now = System.currentTimeMillis();
+ for (String pkg : pkgNames) {
+ enqueueFullBackup(pkg, now);
+ }
}
if (DEBUG) {
diff --git a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
index dc1c9d5..a4489c1 100644
--- a/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
+++ b/services/backup/java/com/android/server/backup/KeyValueBackupJob.java
@@ -41,7 +41,7 @@
// Once someone asks for a backup, this is how long we hold off, batching
// up additional requests, before running the actual backup pass. Privileged
// callers can always trigger an immediate pass via BackupManager.backupNow().
- private static final long BATCH_INTERVAL = 4 * AlarmManager.INTERVAL_HOUR;
+ static final long BATCH_INTERVAL = 4 * AlarmManager.INTERVAL_HOUR;
// Random variation in next-backup scheduling time to avoid server load spikes
private static final int FUZZ_MILLIS = 10 * 60 * 1000;
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 1a0fa34..64b6134 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -10,5 +10,6 @@
java/com/android/server/am/EventLogTags.logtags
LOCAL_JAVA_LIBRARIES := telephony-common
+LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index e6dc1c7..f106667 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -403,13 +403,13 @@
if (cpuCount == 1) {
new ComputeWorker(MIN_SIZE, MAX_SIZE, STEP, bitmaps, pixelCount, results, null).run();
} else {
- int start = MIN_SIZE;
- int end = MAX_SIZE - (cpuCount - 1) * STEP;
+ int start = MIN_SIZE + (cpuCount - 1) * STEP;
+ int end = MAX_SIZE;
int step = STEP * cpuCount;
final CountDownLatch signal = new CountDownLatch(cpuCount);
- for (int i = 0; i < cpuCount; i++, start += STEP, end += STEP) {
+ for (int i = 0; i < cpuCount; i++, start -= STEP, end -= STEP) {
ComputeWorker worker = new ComputeWorker(start, end, step,
bitmaps, pixelCount, results, signal);
new Thread(worker, "Atlas Worker #" + (i + 1)).start();
@@ -435,7 +435,8 @@
if (DEBUG_ATLAS) {
float delay = (System.nanoTime() - begin) / 1000.0f / 1000.0f / 1000.0f;
- Log.d(LOG_TAG, String.format("Found best atlas configuration in %.2fs", delay));
+ Log.d(LOG_TAG, String.format("Found best atlas configuration (out of %d) in %.2fs",
+ results.size(), delay));
}
WorkerResult result = results.get(0);
@@ -696,8 +697,8 @@
Atlas.Entry entry = new Atlas.Entry();
for (Atlas.Type type : Atlas.Type.values()) {
- for (int width = mStart; width < mEnd; width += mStep) {
- for (int height = MIN_SIZE; height < MAX_SIZE; height += STEP) {
+ for (int width = mEnd; width > mStart; width -= mStep) {
+ for (int height = MAX_SIZE; height > MIN_SIZE; height -= STEP) {
// If the atlas is not big enough, skip it
if (width * height <= mThreshold) continue;
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
new file mode 100644
index 0000000..c79fdfc
--- /dev/null
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -0,0 +1,256 @@
+/*
+ * 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.server;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.MemoryFile;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IGraphicsStats;
+import android.view.ThreadedRenderer;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * This service's job is to collect aggregate rendering profile data. It
+ * does this by allowing rendering processes to request an ashmem buffer
+ * to place their stats into. This buffer will be pre-initialized with historical
+ * data for that process if it exists (if the userId & packageName match a buffer
+ * in the historical log)
+ *
+ * This service does not itself attempt to understand the data in the buffer,
+ * its primary job is merely to manage distributing these buffers. However,
+ * it is assumed that this buffer is for ThreadedRenderer and delegates
+ * directly to ThreadedRenderer for dumping buffers.
+ *
+ * MEMORY USAGE:
+ *
+ * This class consumes UP TO:
+ * 1) [active rendering processes] * (ASHMEM_SIZE * 2)
+ * 2) ASHMEM_SIZE (for scratch space used during dumping)
+ * 3) ASHMEM_SIZE * HISTORY_SIZE
+ *
+ * Currently ASHMEM_SIZE is 256 bytes and HISTORY_SIZE is 10. Assuming
+ * the system then also has 10 active rendering processes in the worst case
+ * this would end up using under 10KiB (8KiB for the buffers, plus some overhead
+ * for userId, pid, package name, and a couple other objects)
+ *
+ * @hide */
+public class GraphicsStatsService extends IGraphicsStats.Stub {
+ public static final String GRAPHICS_STATS_SERVICE = "graphicsstats";
+
+ private static final String TAG = "GraphicsStatsService";
+ private static final int ASHMEM_SIZE = 256;
+ private static final int HISTORY_SIZE = 10;
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+ private ArrayList<ActiveBuffer> mActive = new ArrayList<>();
+ private HistoricalData[] mHistoricalLog = new HistoricalData[HISTORY_SIZE];
+ private int mNextHistoricalSlot = 0;
+ private byte[] mTempBuffer = new byte[ASHMEM_SIZE];
+
+ public GraphicsStatsService(Context context) {
+ mContext = context;
+ }
+
+ private boolean isValid(int uid, String packageName) {
+ try {
+ PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
+ return info.applicationInfo.uid == uid;
+ } catch (NameNotFoundException e) {
+ }
+ return false;
+ }
+
+ @Override
+ public ParcelFileDescriptor requestBufferForProcess(String packageName, IBinder token)
+ throws RemoteException {
+ int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+ ParcelFileDescriptor pfd = null;
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ if (!isValid(uid, packageName)) {
+ throw new RemoteException("Invalid package name");
+ }
+ synchronized (mLock) {
+ pfd = requestBufferForProcessLocked(token, uid, pid, packageName);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ return pfd;
+ }
+
+ private ParcelFileDescriptor getPfd(MemoryFile file) {
+ try {
+ return new ParcelFileDescriptor(file.getFileDescriptor());
+ } catch (IOException ex) {
+ throw new IllegalStateException("Failed to get PFD from memory file", ex);
+ }
+ }
+
+ private ParcelFileDescriptor requestBufferForProcessLocked(IBinder token,
+ int uid, int pid, String packageName) throws RemoteException {
+ ActiveBuffer buffer = fetchActiveBuffersLocked(token, uid, pid, packageName);
+ return getPfd(buffer.mProcessBuffer);
+ }
+
+ private void processDied(ActiveBuffer buffer) {
+ synchronized (mLock) {
+ mActive.remove(buffer);
+ Log.d("GraphicsStats", "Buffer count: " + mActive.size());
+ }
+ HistoricalData data = buffer.mPreviousData;
+ buffer.mPreviousData = null;
+ if (data == null) {
+ data = mHistoricalLog[mNextHistoricalSlot];
+ if (data == null) {
+ data = new HistoricalData();
+ }
+ }
+ data.update(buffer.mPackageName, buffer.mUid, buffer.mProcessBuffer);
+ buffer.closeAllBuffers();
+
+ mHistoricalLog[mNextHistoricalSlot] = data;
+ mNextHistoricalSlot = (mNextHistoricalSlot + 1) % mHistoricalLog.length;
+ }
+
+ private ActiveBuffer fetchActiveBuffersLocked(IBinder token, int uid, int pid,
+ String packageName) throws RemoteException {
+ int size = mActive.size();
+ for (int i = 0; i < size; i++) {
+ ActiveBuffer buffers = mActive.get(i);
+ if (buffers.mPid == pid
+ && buffers.mUid == uid) {
+ return buffers;
+ }
+ }
+ // Didn't find one, need to create it
+ try {
+ ActiveBuffer buffers = new ActiveBuffer(token, uid, pid, packageName);
+ mActive.add(buffers);
+ return buffers;
+ } catch (IOException ex) {
+ throw new RemoteException("Failed to allocate space");
+ }
+ }
+
+ private HistoricalData removeHistoricalDataLocked(int uid, String packageName) {
+ for (int i = 0; i < mHistoricalLog.length; i++) {
+ final HistoricalData data = mHistoricalLog[i];
+ if (data != null && data.mUid == uid
+ && data.mPackageName.equals(packageName)) {
+ if (i == mNextHistoricalSlot) {
+ mHistoricalLog[i] = null;
+ } else {
+ mHistoricalLog[i] = mHistoricalLog[mNextHistoricalSlot];
+ mHistoricalLog[mNextHistoricalSlot] = null;
+ }
+ return data;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+ synchronized (mLock) {
+ for (int i = 0; i < mActive.size(); i++) {
+ final ActiveBuffer buffer = mActive.get(i);
+ fout.print("Package: ");
+ fout.print(buffer.mPackageName);
+ fout.flush();
+ try {
+ buffer.mProcessBuffer.readBytes(mTempBuffer, 0, 0, ASHMEM_SIZE);
+ ThreadedRenderer.dumpProfileData(mTempBuffer, fd);
+ } catch (IOException e) {
+ fout.println("Failed to dump");
+ }
+ fout.println();
+ }
+ for (HistoricalData buffer : mHistoricalLog) {
+ if (buffer == null) continue;
+ fout.print("Package: ");
+ fout.print(buffer.mPackageName);
+ fout.flush();
+ ThreadedRenderer.dumpProfileData(buffer.mBuffer, fd);
+ fout.println();
+ }
+ }
+ }
+
+ private final class ActiveBuffer implements DeathRecipient {
+ final int mUid;
+ final int mPid;
+ final String mPackageName;
+ final IBinder mToken;
+ MemoryFile mProcessBuffer;
+ HistoricalData mPreviousData;
+
+ ActiveBuffer(IBinder token, int uid, int pid, String packageName)
+ throws RemoteException, IOException {
+ mUid = uid;
+ mPid = pid;
+ mPackageName = packageName;
+ mToken = token;
+ mToken.linkToDeath(this, 0);
+ mProcessBuffer = new MemoryFile("GFXStats-" + uid, ASHMEM_SIZE);
+ mPreviousData = removeHistoricalDataLocked(mUid, mPackageName);
+ if (mPreviousData != null) {
+ mProcessBuffer.writeBytes(mPreviousData.mBuffer, 0, 0, ASHMEM_SIZE);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ mToken.unlinkToDeath(this, 0);
+ processDied(this);
+ }
+
+ void closeAllBuffers() {
+ if (mProcessBuffer != null) {
+ mProcessBuffer.close();
+ mProcessBuffer = null;
+ }
+ }
+ }
+
+ private final static class HistoricalData {
+ final byte[] mBuffer = new byte[ASHMEM_SIZE];
+ int mUid;
+ String mPackageName;
+
+ void update(String packageName, int uid, MemoryFile file) {
+ mUid = uid;
+ mPackageName = packageName;
+ try {
+ file.readBytes(mBuffer, 0, 0, ASHMEM_SIZE);
+ } catch (IOException e) {}
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index cea1ebe..744156b 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -47,6 +47,7 @@
final private static String TAG = "IntentResolver";
final private static boolean DEBUG = false;
final private static boolean localLOGV = DEBUG || false;
+ final private static boolean localVerificationLOGV = DEBUG || false;
public void addFilter(F f) {
if (localLOGV) {
@@ -478,7 +479,7 @@
/**
* Returns whether the object associated with the given filter is
- * "stopped," that is whether it should not be included in the result
+ * "stopped", that is whether it should not be included in the result
* if the intent requests to excluded stopped objects.
*/
protected boolean isFilterStopped(F filter, int userId) {
@@ -486,6 +487,22 @@
}
/**
+ * Returns whether the given filter is "verified" that is whether it has been verified against
+ * its data URIs.
+ *
+ * The verification would happen only and only if the Intent action is
+ * {@link android.content.Intent#ACTION_VIEW} and the Intent category is
+ * {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent data scheme
+ * is "http" or "https".
+ *
+ * @see android.content.IntentFilter#setAutoVerify(boolean)
+ * @see android.content.IntentFilter#getAutoVerify()
+ */
+ protected boolean isFilterVerified(F filter) {
+ return filter.isVerified();
+ }
+
+ /**
* Returns whether this filter is owned by this package. This must be
* implemented to provide correct filtering of Intents that have
* specified a package name they are to be delivered to.
@@ -710,6 +727,13 @@
continue;
}
+ // Are we verified ?
+ if (filter.getAutoVerify()) {
+ if (localVerificationLOGV || debug) {
+ Slog.v(TAG, " Filter verified: " + isFilterVerified(filter));
+ }
+ }
+
// Do we already have this one?
if (!allowFilterResult(filter, dest)) {
if (debug) {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index b8d9ec5..61286e8 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -16,29 +16,21 @@
package com.android.server;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
import android.Manifest;
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.ObbInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.hardware.usb.UsbManager;
+import android.mtp.MtpStorage;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -59,26 +51,24 @@
import android.os.storage.StorageResultCode;
import android.os.storage.StorageVolume;
import android.text.TextUtils;
-import android.util.AttributeSet;
+import android.util.ArrayMap;
+import android.util.DebugUtils;
import android.util.Slog;
-import android.util.Xml;
+import android.util.SparseArray;
+
+import libcore.util.EmptyArray;
+import libcore.util.HexEncoding;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IMediaContainerService;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
import com.android.server.NativeDaemonConnector.Command;
import com.android.server.NativeDaemonConnector.SensitiveArg;
-import com.android.server.am.ActivityManagerService;
import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.UserManagerService;
import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
-import libcore.util.HexEncoding;
-
-import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileDescriptor;
@@ -101,7 +91,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -110,19 +99,18 @@
import javax.crypto.spec.PBEKeySpec;
/**
- * MountService implements back-end services for platform storage
- * management.
- * @hide - Applications should use android.os.storage.StorageManager
- * to access the MountService.
+ * Service responsible for various storage media. Connects to {@code vold} to
+ * watch for and manage dynamically added storage, such as SD cards and USB mass
+ * storage. Also decides how storage should be presented to users on the device.
*/
class MountService extends IMountService.Stub
implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
+ // TODO: finish enforcing UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA
+
// Static direct instance pointer for the tightly-coupled idle service to use
static MountService sSelf = null;
- // TODO: listen for user creation/deletion
-
public static class Lifecycle extends SystemService {
private MountService mMountService;
@@ -142,6 +130,16 @@
mMountService.systemReady();
}
}
+
+ @Override
+ public void onStartUser(int userHandle) {
+ mMountService.onStartUser(userHandle);
+ }
+
+ @Override
+ public void onCleanupUser(int userHandle) {
+ mMountService.onCleanupUser(userHandle);
+ }
}
private static final boolean LOCAL_LOGD = false;
@@ -159,21 +157,7 @@
/** Maximum number of ASEC containers allowed to be mounted. */
private static final int MAX_CONTAINERS = 250;
- /*
- * Internal vold volume state constants
- */
- class VolumeState {
- public static final int Init = -1;
- public static final int NoMedia = 0;
- public static final int Idle = 1;
- public static final int Pending = 2;
- public static final int Checking = 3;
- public static final int Mounted = 4;
- public static final int Unmounting = 5;
- public static final int Formatting = 6;
- public static final int Shared = 7;
- public static final int SharedMnt = 8;
- }
+ private static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
/*
* Internal vold response code constants
@@ -209,12 +193,19 @@
/*
* 600 series - Unsolicited broadcasts.
*/
- public static final int VolumeStateChange = 605;
- public static final int VolumeUuidChange = 613;
- public static final int VolumeUserLabelChange = 614;
- public static final int VolumeDiskInserted = 630;
- public static final int VolumeDiskRemoved = 631;
- public static final int VolumeBadRemoval = 632;
+ public static final int DISK_CREATED = 640;
+ public static final int DISK_SIZE_CHANGED = 641;
+ public static final int DISK_LABEL_CHANGED = 642;
+ public static final int DISK_VOLUME_CREATED = 643;
+ public static final int DISK_DESTROYED = 649;
+
+ public static final int VOLUME_CREATED = 650;
+ public static final int VOLUME_STATE_CHANGED = 651;
+ public static final int VOLUME_FS_TYPE_CHANGED = 652;
+ public static final int VOLUME_FS_UUID_CHANGED = 653;
+ public static final int VOLUME_FS_LABEL_CHANGED = 654;
+ public static final int VOLUME_PATH_CHANGED = 655;
+ public static final int VOLUME_DESTROYED = 659;
/*
* 700 series - fstrim
@@ -222,6 +213,243 @@
public static final int FstrimCompleted = 700;
}
+ private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
+ private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
+
+ static {
+ sStateToEnvironment.put(Volume.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
+ sStateToEnvironment.put(Volume.STATE_MOUNTING, Environment.MEDIA_CHECKING);
+ sStateToEnvironment.put(Volume.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
+ sStateToEnvironment.put(Volume.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
+ sStateToEnvironment.put(Volume.STATE_UNMOUNTING, Environment.MEDIA_EJECTING);
+
+ sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
+ sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
+ sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
+ sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
+ }
+
+ /**
+ * <em>Never</em> hold the lock while performing downcalls into vold, since
+ * unsolicited events can suddenly appear to update data structures.
+ */
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private int[] mStartedUsers = EmptyArray.INT;
+ @GuardedBy("mLock")
+ private ArrayMap<String, Disk> mDisks = new ArrayMap<>();
+ @GuardedBy("mLock")
+ private ArrayMap<String, Volume> mVolumes = new ArrayMap<>();
+
+ @Deprecated
+ private Volume findVolumeByLegacyPath(String legacyPath) {
+ synchronized (mLock) {
+ for (Volume vol : mVolumes.values()) {
+ if (vol.path != null && legacyPath.startsWith(vol.path)) {
+ return vol;
+ }
+ }
+ }
+ Slog.w(TAG, "Failed to find volume for path " + legacyPath);
+ return null;
+ }
+
+ /**
+ * Framework-side twin of android::vold::Disk
+ */
+ private class Disk {
+ public static final int FLAG_ADOPTABLE = 1 << 0;
+ public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
+ public static final int FLAG_SD = 1 << 2;
+ public static final int FLAG_USB = 1 << 3;
+
+ public final String id;
+ public final int flags;
+ public long size;
+ public String label;
+
+ public ArrayList<Volume> volumes = new ArrayList<>();
+
+ public Disk(String id, int flags) {
+ this.id = id;
+ this.flags = flags;
+ }
+
+ public void partitionPublic() throws NativeDaemonConnectorException {
+ mConnector.execute("volume", "partition", id, "public");
+ }
+
+ public void partitionPrivate() throws NativeDaemonConnectorException {
+ mConnector.execute("volume", "partition", id, "private");
+ }
+
+ public void partitionMixed(int frac) throws NativeDaemonConnectorException {
+ mConnector.execute("volume", "partition", id, "mixed", frac);
+ }
+
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("Disk:");
+ pw.increaseIndent();
+ pw.printPair("id", id);
+ pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
+ pw.printPair("size", size);
+ pw.printPair("label", label);
+ pw.decreaseIndent();
+ pw.println();
+ }
+ }
+
+ private static int sNextMtpIndex = 1;
+
+ /**
+ * Framework-side twin of android::vold::VolumeBase
+ */
+ private class Volume {
+ public static final String ID_EMULATED_INTERNAL = "emulated";
+
+ public static final int TYPE_PUBLIC = 0;
+ public static final int TYPE_PRIVATE = 1;
+ public static final int TYPE_EMULATED = 2;
+ public static final int TYPE_ASEC = 3;
+ public static final int TYPE_OBB = 4;
+
+ public static final int STATE_UNMOUNTED = 0;
+ public static final int STATE_MOUNTING = 1;
+ public static final int STATE_MOUNTED = 2;
+ public static final int STATE_FORMATTING = 3;
+ public static final int STATE_UNMOUNTING = 4;
+
+ public static final int FLAG_PRIMARY = 1 << 0;
+ public static final int FLAG_VISIBLE = 1 << 1;
+
+ /** vold state */
+ public final String id;
+ public final int type;
+ public int flags = 0;
+ public int userId = -1;
+ public int state = STATE_UNMOUNTED;
+ public String fsType;
+ public String fsUuid;
+ public String fsLabel;
+ public String path = "/dev/null";
+
+ /** Framework state */
+ public final int mtpIndex;
+
+ public Disk disk;
+
+ public Volume(String id, int type) {
+ this.id = id;
+ this.type = type;
+
+ if (ID_EMULATED_INTERNAL.equals(id)) {
+ mtpIndex = 0;
+ } else {
+ mtpIndex = sNextMtpIndex++;
+ }
+ }
+
+ public boolean isPrimary() {
+ return (flags & FLAG_PRIMARY) != 0;
+ }
+
+ public boolean isVisible() {
+ return (flags & FLAG_VISIBLE) != 0;
+ }
+
+ public boolean isVisibleToUser(int userId) {
+ if (type == TYPE_PUBLIC && this.userId == userId) {
+ return isVisible();
+ } else if (type == TYPE_EMULATED) {
+ return isVisible();
+ } else {
+ return false;
+ }
+ }
+
+ public void mount() throws NativeDaemonConnectorException {
+ mConnector.execute("volume", "mount", id, flags, userId);
+ }
+
+ public void unmount() throws NativeDaemonConnectorException {
+ mConnector.execute("volume", "unmount", id);
+ }
+
+ public void format() throws NativeDaemonConnectorException {
+ mConnector.execute("volume", "format", id);
+ }
+
+ public StorageVolume buildVolumeForUser(int userId) {
+ final File userPath;
+ final boolean removable;
+ final boolean emulated;
+ final boolean allowMassStorage = false;
+ final int mtpStorageId = MtpStorage.getStorageIdForIndex(mtpIndex);
+ final String envState = sStateToEnvironment.get(state);
+
+ int descriptionId = com.android.internal.R.string.unknownName;
+ long mtpReserveSize = 0;
+ long maxFileSize = 0;
+
+ if (type == TYPE_EMULATED) {
+ userPath = new File(path, Integer.toString(userId));
+ emulated = true;
+ mtpReserveSize = StorageManager.from(mContext).getStorageLowBytes(userPath);
+ descriptionId = com.android.internal.R.string.storage_internal;
+
+ if (ID_EMULATED_INTERNAL.equals(id)) {
+ removable = false;
+ } else {
+ removable = true;
+ }
+
+ } else if (type == TYPE_PUBLIC) {
+ userPath = new File(path);
+ emulated = false;
+ removable = true;
+
+ if (disk != null) {
+ if ((disk.flags & Disk.FLAG_SD) != 0) {
+ descriptionId = com.android.internal.R.string.storage_sd_card;
+ } else if ((disk.flags & Disk.FLAG_USB) != 0) {
+ descriptionId = com.android.internal.R.string.storage_usb;
+ }
+ }
+
+ if ("vfat".equals(fsType)) {
+ maxFileSize = 4294967295L;
+ }
+
+ } else {
+ throw new IllegalStateException("Unexpected volume type " + type);
+ }
+
+ return new StorageVolume(id, mtpStorageId, userPath, descriptionId, isPrimary(),
+ removable, emulated, mtpReserveSize, allowMassStorage, maxFileSize,
+ new UserHandle(userId), fsUuid, fsLabel, envState);
+ }
+
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("Volume:");
+ pw.increaseIndent();
+ pw.printPair("id", id);
+ pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
+ pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
+ pw.printPair("userId", userId);
+ pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
+ pw.println();
+ pw.printPair("fsType", fsType);
+ pw.printPair("fsUuid", fsUuid);
+ pw.printPair("fsLabel", fsLabel);
+ pw.println();
+ pw.printPair("path", path);
+ pw.printPair("mtpIndex", mtpIndex);
+ pw.decreaseIndent();
+ pw.println();
+ }
+ }
+
/** List of crypto types.
* These must match CRYPT_TYPE_XXX in cryptfs.h AND their
* corresponding commands in CommandListener.cpp */
@@ -231,33 +459,20 @@
private final Context mContext;
private final NativeDaemonConnector mConnector;
- private final Object mVolumesLock = new Object();
-
- /** When defined, base template for user-specific {@link StorageVolume}. */
- private StorageVolume mEmulatedTemplate;
-
- // TODO: separate storage volumes on per-user basis
-
- @GuardedBy("mVolumesLock")
- private final ArrayList<StorageVolume> mVolumes = Lists.newArrayList();
- /** Map from path to {@link StorageVolume} */
- @GuardedBy("mVolumesLock")
- private final HashMap<String, StorageVolume> mVolumesByPath = Maps.newHashMap();
- /** Map from path to state */
- @GuardedBy("mVolumesLock")
- private final HashMap<String, String> mVolumeStates = Maps.newHashMap();
-
private volatile boolean mSystemReady = false;
+ private volatile boolean mDaemonConnected = false;
private PackageManagerService mPms;
- private boolean mUmsEnabling;
- private boolean mUmsAvailable = false;
// Used as a lock for methods that register/unregister listeners.
final private ArrayList<MountServiceBinderListener> mListeners =
new ArrayList<MountServiceBinderListener>();
+
private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
- private boolean mSendUmsConnectedOnBoot = false;
+
+ private final Object mUnmountLock = new Object();
+ @GuardedBy("mUnmountLock")
+ private CountDownLatch mUnmountSignal;
/**
* Private hash of currently mounted secure containers.
@@ -366,6 +581,7 @@
final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
class DefaultContainerConnection implements ServiceConnection {
+ @Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG_OBB)
Slog.i(TAG, "onServiceConnected");
@@ -373,6 +589,7 @@
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
}
+ @Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG_OBB)
Slog.i(TAG, "onServiceDisconnected");
@@ -388,177 +605,27 @@
private long mLastMaintenance;
// Handler messages
- private static final int H_UNMOUNT_PM_UPDATE = 1;
- private static final int H_UNMOUNT_PM_DONE = 2;
- private static final int H_UNMOUNT_MS = 3;
- private static final int H_SYSTEM_READY = 4;
- private static final int H_FSTRIM = 5;
-
- private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
- private static final int MAX_UNMOUNT_RETRIES = 4;
-
- class UnmountCallBack {
- final String path;
- final boolean force;
- final boolean removeEncryption;
- int retries;
-
- UnmountCallBack(String path, boolean force, boolean removeEncryption) {
- retries = 0;
- this.path = path;
- this.force = force;
- this.removeEncryption = removeEncryption;
- }
-
- void handleFinished() {
- if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path);
- doUnmountVolume(path, true, removeEncryption);
- }
- }
-
- class UmsEnableCallBack extends UnmountCallBack {
- final String method;
-
- UmsEnableCallBack(String path, String method, boolean force) {
- super(path, force, false);
- this.method = method;
- }
-
- @Override
- void handleFinished() {
- super.handleFinished();
- doShareUnshareVolume(path, method, true);
- }
- }
-
- class ShutdownCallBack extends UnmountCallBack {
- MountShutdownLatch mMountShutdownLatch;
- ShutdownCallBack(String path, final MountShutdownLatch mountShutdownLatch) {
- super(path, true, false);
- mMountShutdownLatch = mountShutdownLatch;
- }
-
- @Override
- void handleFinished() {
- int ret = doUnmountVolume(path, true, removeEncryption);
- Slog.i(TAG, "Unmount completed: " + path + ", result code: " + ret);
- mMountShutdownLatch.countDown();
- }
- }
-
- static class MountShutdownLatch {
- private IMountShutdownObserver mObserver;
- private AtomicInteger mCount;
-
- MountShutdownLatch(final IMountShutdownObserver observer, int count) {
- mObserver = observer;
- mCount = new AtomicInteger(count);
- }
-
- void countDown() {
- boolean sendShutdown = false;
- if (mCount.decrementAndGet() == 0) {
- sendShutdown = true;
- }
- if (sendShutdown && mObserver != null) {
- try {
- mObserver.onShutDownComplete(StorageResultCode.OperationSucceeded);
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException when shutting down");
- }
- }
- }
- }
+ private static final int H_SYSTEM_READY = 1;
+ private static final int H_DAEMON_CONNECTED = 2;
+ private static final int H_SHUTDOWN = 3;
+ private static final int H_FSTRIM = 4;
+ private static final int H_VOLUME_MOUNT = 5;
+ private static final int H_VOLUME_BROADCAST = 6;
class MountServiceHandler extends Handler {
- ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
- boolean mUpdatingStatus = false;
-
- MountServiceHandler(Looper l) {
- super(l);
+ public MountServiceHandler(Looper looper) {
+ super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case H_UNMOUNT_PM_UPDATE: {
- if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE");
- UnmountCallBack ucb = (UnmountCallBack) msg.obj;
- mForceUnmounts.add(ucb);
- if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus);
- // Register only if needed.
- if (!mUpdatingStatus) {
- if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");
- mUpdatingStatus = true;
- mPms.updateExternalMediaStatus(false, true);
- }
- break;
- }
- case H_UNMOUNT_PM_DONE: {
- if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE");
- if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests");
- mUpdatingStatus = false;
- int size = mForceUnmounts.size();
- int sizeArr[] = new int[size];
- int sizeArrN = 0;
- // Kill processes holding references first
- ActivityManagerService ams = (ActivityManagerService)
- ServiceManager.getService("activity");
- for (int i = 0; i < size; i++) {
- UnmountCallBack ucb = mForceUnmounts.get(i);
- String path = ucb.path;
- boolean done = false;
- if (!ucb.force) {
- done = true;
- } else {
- int pids[] = getStorageUsers(path);
- if (pids == null || pids.length == 0) {
- done = true;
- } else {
- // Eliminate system process here?
- ams.killPids(pids, "unmount media", true);
- // Confirm if file references have been freed.
- pids = getStorageUsers(path);
- if (pids == null || pids.length == 0) {
- done = true;
- }
- }
- }
- if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
- // Retry again
- Slog.i(TAG, "Retrying to kill storage users again");
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
- ucb.retries++),
- RETRY_UNMOUNT_DELAY);
- } else {
- if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
- Slog.i(TAG, "Failed to unmount media inspite of " +
- MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");
- }
- sizeArr[sizeArrN++] = i;
- mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
- ucb));
- }
- }
- // Remove already processed elements from list.
- for (int i = (sizeArrN-1); i >= 0; i--) {
- mForceUnmounts.remove(sizeArr[i]);
- }
- break;
- }
- case H_UNMOUNT_MS: {
- if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS");
- UnmountCallBack ucb = (UnmountCallBack) msg.obj;
- ucb.handleFinished();
- break;
- }
case H_SYSTEM_READY: {
- try {
- handleSystemReady();
- } catch (Exception ex) {
- Slog.e(TAG, "Boot-time mount exception", ex);
- }
+ handleSystemReady();
+ break;
+ }
+ case H_DAEMON_CONNECTED: {
+ handleDaemonConnected();
break;
}
case H_FSTRIM: {
@@ -589,29 +656,68 @@
}
break;
}
+ case H_SHUTDOWN: {
+ final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
+ boolean success = false;
+ try {
+ success = mConnector.execute("volume", "shutdown").isClassOk();
+ } catch (NativeDaemonConnectorException ignored) {
+ }
+ if (obs != null) {
+ try {
+ obs.onShutDownComplete(success ? 0 : -1);
+ } catch (RemoteException ignored) {
+ }
+ }
+ break;
+ }
+ case H_VOLUME_MOUNT: {
+ final Volume vol = (Volume) msg.obj;
+ try {
+ vol.mount();
+ } catch (NativeDaemonConnectorException ignored) {
+ }
+ break;
+ }
+ case H_VOLUME_BROADCAST: {
+ final StorageVolume userVol = (StorageVolume) msg.obj;
+ final String state = userVol.getState();
+ Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + state + " to "
+ + userVol.getOwner());
+
+ final String action = sEnvironmentToBroadcast.get(state);
+ if (action != null) {
+ final Intent intent = new Intent(action,
+ Uri.fromFile(userVol.getPathFile()));
+ intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(intent, userVol.getOwner());
+ }
+ break;
+ }
}
}
- };
+ }
private final Handler mHandler;
@Override
public void waitForAsecScan() {
- waitForLatch(mAsecsScanned);
+ waitForLatch(mAsecsScanned, "mAsecsScanned");
}
private void waitForReady() {
- waitForLatch(mConnectedSignal);
+ waitForLatch(mConnectedSignal, "mConnectedSignal");
}
- private void waitForLatch(CountDownLatch latch) {
+ private void waitForLatch(CountDownLatch latch, String condition) {
for (;;) {
try {
if (latch.await(5000, TimeUnit.MILLISECONDS)) {
return;
} else {
Slog.w(TAG, "Thread " + Thread.currentThread().getName()
- + " still waiting for MountService ready...");
+ + " still waiting for " + condition + "...");
}
} catch (InterruptedException e) {
Slog.w(TAG, "Interrupt while waiting for MountService to be ready.");
@@ -628,103 +734,72 @@
}
private void handleSystemReady() {
- // Snapshot current volume states since it's not safe to call into vold
- // while holding locks.
- final HashMap<String, String> snapshot;
- synchronized (mVolumesLock) {
- snapshot = new HashMap<String, String>(mVolumeStates);
- }
+ resetIfReadyAndConnected();
- for (Map.Entry<String, String> entry : snapshot.entrySet()) {
- final String path = entry.getKey();
- final String state = entry.getValue();
-
- if (state.equals(Environment.MEDIA_UNMOUNTED)) {
- int rc = doMountVolume(path);
- if (rc != StorageResultCode.OperationSucceeded) {
- Slog.e(TAG, String.format("Boot-time mount failed (%d)",
- rc));
- }
- } else if (state.equals(Environment.MEDIA_SHARED)) {
- /*
- * Bootstrap UMS enabled state since vold indicates
- * the volume is shared (runtime restart while ums enabled)
- */
- notifyVolumeStateChange(null, path, VolumeState.NoMedia,
- VolumeState.Shared);
- }
- }
-
- // Push mounted state for all emulated storage
- synchronized (mVolumesLock) {
- for (StorageVolume volume : mVolumes) {
- if (volume.isEmulated()) {
- updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
- }
- }
- }
-
- /*
- * If UMS was connected on boot, send the connected event
- * now that we're up.
- */
- if (mSendUmsConnectedOnBoot) {
- sendUmsIntent(true);
- mSendUmsConnectedOnBoot = false;
- }
-
- /*
- * Start scheduling nominally-daily fstrim operations
- */
+ // Start scheduling nominally-daily fstrim operations
MountServiceIdler.scheduleIdlePass(mContext);
}
- private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- if (userId == -1) return;
- final UserHandle user = new UserHandle(userId);
+ private void resetIfReadyAndConnected() {
+ Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
+ + ", mDaemonConnected=" + mDaemonConnected);
+ if (mSystemReady && mDaemonConnected) {
+ mDisks.clear();
+ mVolumes.clear();
- final String action = intent.getAction();
- if (Intent.ACTION_USER_ADDED.equals(action)) {
- synchronized (mVolumesLock) {
- createEmulatedVolumeForUserLocked(user);
- }
-
- } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
- synchronized (mVolumesLock) {
- final List<StorageVolume> toRemove = Lists.newArrayList();
- for (StorageVolume volume : mVolumes) {
- if (user.equals(volume.getOwner())) {
- toRemove.add(volume);
- }
- }
- for (StorageVolume volume : toRemove) {
- removeVolumeLocked(volume);
- }
- }
+ try {
+ mConnector.execute("volume", "reset");
+ } catch (NativeDaemonConnectorException e) {
+ Slog.w(TAG, "Failed to reset vold", e);
}
}
- };
+ }
- private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) &&
- intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false));
- notifyShareAvailabilityChange(available);
+ private void onStartUser(int userId) {
+ Slog.d(TAG, "onStartUser " + userId);
+
+ // We purposefully block here to make sure that user-specific
+ // staging area is ready so it's ready for zygote-forked apps to
+ // bind mount against.
+ try {
+ mConnector.execute("volume", "start_user", userId);
+ } catch (NativeDaemonConnectorException ignored) {
}
- };
+
+ // Record user as started so newly mounted volumes kick off events
+ // correctly, then synthesize events for any already-mounted volumes.
+ synchronized (mVolumes) {
+ for (Volume vol : mVolumes.values()) {
+ if (vol.isVisibleToUser(userId) && vol.state == Volume.STATE_MOUNTED) {
+ final StorageVolume userVol = vol.buildVolumeForUser(userId);
+ mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
+ }
+ }
+ mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userId);
+ }
+ }
+
+ private void onCleanupUser(int userId) {
+ Slog.d(TAG, "onCleanupUser " + userId);
+
+ try {
+ mConnector.execute("volume", "cleanup_user", userId);
+ } catch (NativeDaemonConnectorException ignored) {
+ }
+
+ synchronized (mVolumes) {
+ mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userId);
+ }
+ }
private final class MountServiceBinderListener implements IBinder.DeathRecipient {
final IMountServiceListener mListener;
MountServiceBinderListener(IMountServiceListener listener) {
mListener = listener;
-
}
+ @Override
public void binderDied() {
if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
synchronized (mListeners) {
@@ -741,7 +816,7 @@
// Binder entry point for kicking off an immediate fstrim
@Override
public void runMaintenance() {
- validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
runIdleMaintenance(null);
}
@@ -750,144 +825,35 @@
return mLastMaintenance;
}
- private void doShareUnshareVolume(String path, String method, boolean enable) {
- // TODO: Add support for multiple share methods
- if (!method.equals("ums")) {
- throw new IllegalArgumentException(String.format("Method %s not supported", method));
- }
-
- try {
- mConnector.execute("volume", enable ? "share" : "unshare", path, method);
- } catch (NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to share/unshare", e);
- }
- }
-
- private void updatePublicVolumeState(StorageVolume volume, String state) {
- final String path = volume.getPath();
- final String oldState;
- synchronized (mVolumesLock) {
- oldState = mVolumeStates.put(path, state);
- volume.setState(state);
- }
-
- if (state.equals(oldState)) {
- Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",
- state, state, path));
- return;
- }
-
- Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");
-
- // Tell PackageManager about changes to primary volume state, but only
- // when not emulated.
- if (volume.isPrimary() && !volume.isEmulated()) {
- if (Environment.MEDIA_UNMOUNTED.equals(state)) {
- mPms.updateExternalMediaStatus(false, false);
-
- /*
- * Some OBBs might have been unmounted when this volume was
- * unmounted, so send a message to the handler to let it know to
- * remove those from the list of mounted OBBS.
- */
- mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
- OBB_FLUSH_MOUNT_STATE, path));
- } else if (Environment.MEDIA_MOUNTED.equals(state)) {
- mPms.updateExternalMediaStatus(true, false);
- }
- }
-
- synchronized (mListeners) {
- for (int i = mListeners.size() -1; i >= 0; i--) {
- MountServiceBinderListener bl = mListeners.get(i);
- try {
- bl.mListener.onStorageStateChanged(path, oldState, state);
- } catch (RemoteException rex) {
- Slog.e(TAG, "Listener dead");
- mListeners.remove(i);
- } catch (Exception ex) {
- Slog.e(TAG, "Listener failed", ex);
- }
- }
- }
- }
-
/**
* Callback from NativeDaemonConnector
*/
+ @Override
public void onDaemonConnected() {
+ mDaemonConnected = true;
+ mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
+ }
+
+ private void handleDaemonConnected() {
+ resetIfReadyAndConnected();
+
/*
- * Since we'll be calling back into the NativeDaemonConnector,
- * we need to do our work in a new thread.
+ * Now that we've done our initialization, release
+ * the hounds!
*/
- new Thread("MountService#onDaemonConnected") {
- @Override
- public void run() {
- /**
- * Determine media state and UMS detection status
- */
- try {
- final String[] vols = NativeDaemonEvent.filterMessageList(
- mConnector.executeForList("volume", "list", "broadcast"),
- VoldResponseCode.VolumeListResult);
- for (String volstr : vols) {
- String[] tok = volstr.split(" ");
- // FMT: <label> <mountpoint> <state>
- String path = tok[1];
- String state = Environment.MEDIA_REMOVED;
+ mConnectedSignal.countDown();
- final StorageVolume volume;
- synchronized (mVolumesLock) {
- volume = mVolumesByPath.get(path);
- }
+ // On an encrypted device we can't see system properties yet, so pull
+ // the system locale out of the mount service.
+ if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
+ copyLocaleFromMountService();
+ }
- int st = Integer.parseInt(tok[2]);
- if (st == VolumeState.NoMedia) {
- state = Environment.MEDIA_REMOVED;
- } else if (st == VolumeState.Idle) {
- state = Environment.MEDIA_UNMOUNTED;
- } else if (st == VolumeState.Mounted) {
- state = Environment.MEDIA_MOUNTED;
- Slog.i(TAG, "Media already mounted on daemon connection");
- } else if (st == VolumeState.Shared) {
- state = Environment.MEDIA_SHARED;
- Slog.i(TAG, "Media shared on daemon connection");
- } else {
- throw new Exception(String.format("Unexpected state %d", st));
- }
+ // Let package manager load internal ASECs.
+ mPms.scanAvailableAsecs();
- if (state != null) {
- if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
- updatePublicVolumeState(volume, state);
- }
- }
- } catch (Exception e) {
- Slog.e(TAG, "Error processing initial volume state", e);
- final StorageVolume primary = getPrimaryPhysicalVolume();
- if (primary != null) {
- updatePublicVolumeState(primary, Environment.MEDIA_REMOVED);
- }
- }
-
- /*
- * Now that we've done our initialization, release
- * the hounds!
- */
- mConnectedSignal.countDown();
-
- // On an encrypted device we can't see system properties yet, so pull
- // the system locale out of the mount service.
- if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
- copyLocaleFromMountService();
- }
-
- // Let package manager load internal ASECs.
- mPms.scanAvailableAsecs();
-
- // Notify people waiting for ASECs to be scanned that it's done.
- mAsecsScanned.countDown();
- }
- }.start();
+ // Notify people waiting for ASECs to be scanned that it's done.
+ mAsecsScanned.countDown();
}
private void copyLocaleFromMountService() {
@@ -919,6 +885,7 @@
/**
* Callback from NativeDaemonConnector
*/
+ @Override
public boolean onCheckHoldWakeLock(int code) {
return false;
}
@@ -926,347 +893,182 @@
/**
* Callback from NativeDaemonConnector
*/
+ @Override
public boolean onEvent(int code, String raw, String[] cooked) {
- if (DEBUG_EVENTS) {
- StringBuilder builder = new StringBuilder();
- builder.append("onEvent::");
- builder.append(" raw= " + raw);
- if (cooked != null) {
- builder.append(" cooked = " );
- for (String str : cooked) {
- builder.append(" " + str);
- }
- }
- Slog.i(TAG, builder.toString());
+ synchronized (mLock) {
+ return onEventLocked(code, raw, cooked);
}
- if (code == VoldResponseCode.VolumeStateChange) {
- /*
- * One of the volumes we're managing has changed state.
- * Format: "NNN Volume <label> <path> state changed
- * from <old_#> (<old_str>) to <new_#> (<new_str>)"
- */
- notifyVolumeStateChange(
- cooked[2], cooked[3], Integer.parseInt(cooked[7]),
- Integer.parseInt(cooked[10]));
- } else if (code == VoldResponseCode.VolumeUuidChange) {
- // Format: nnn <label> <path> <uuid>
- final String path = cooked[2];
- final String uuid = (cooked.length > 3) ? cooked[3] : null;
+ }
- final StorageVolume vol = mVolumesByPath.get(path);
- if (vol != null) {
- vol.setUuid(uuid);
+ private boolean onEventLocked(int code, String raw, String[] cooked) {
+ switch (code) {
+ case VoldResponseCode.DISK_CREATED: {
+ if (cooked.length != 3) break;
+ final String id = cooked[1];
+ final int flags = Integer.parseInt(cooked[2]);
+ mDisks.put(id, new Disk(id, flags));
+ break;
}
-
- } else if (code == VoldResponseCode.VolumeUserLabelChange) {
- // Format: nnn <label> <path> <label>
- final String path = cooked[2];
- final String userLabel = (cooked.length > 3) ? cooked[3] : null;
-
- final StorageVolume vol = mVolumesByPath.get(path);
- if (vol != null) {
- vol.setUserLabel(userLabel);
- }
-
- } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
- (code == VoldResponseCode.VolumeDiskRemoved) ||
- (code == VoldResponseCode.VolumeBadRemoval)) {
- // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
- // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
- // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
- String action = null;
- final String label = cooked[2];
- final String path = cooked[3];
- int major = -1;
- int minor = -1;
-
- try {
- String devComp = cooked[6].substring(1, cooked[6].length() -1);
- String[] devTok = devComp.split(":");
- major = Integer.parseInt(devTok[0]);
- minor = Integer.parseInt(devTok[1]);
- } catch (Exception ex) {
- Slog.e(TAG, "Failed to parse major/minor", ex);
- }
-
- final StorageVolume volume;
- final String state;
- synchronized (mVolumesLock) {
- volume = mVolumesByPath.get(path);
- state = mVolumeStates.get(path);
- }
-
- if (code == VoldResponseCode.VolumeDiskInserted) {
- new Thread("MountService#VolumeDiskInserted") {
- @Override
- public void run() {
- try {
- int rc;
- if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
- Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
- }
- } catch (Exception ex) {
- Slog.w(TAG, "Failed to mount media on insertion", ex);
- }
- }
- }.start();
- } else if (code == VoldResponseCode.VolumeDiskRemoved) {
- /*
- * This event gets trumped if we're already in BAD_REMOVAL state
- */
- if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
- return true;
+ case VoldResponseCode.DISK_SIZE_CHANGED: {
+ if (cooked.length != 3) break;
+ final Disk disk = mDisks.get(cooked[1]);
+ if (disk != null) {
+ disk.size = Long.parseLong(cooked[2]);
}
- /* Send the media unmounted event first */
- if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
- updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
- sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);
+ break;
+ }
+ case VoldResponseCode.DISK_LABEL_CHANGED: {
+ if (cooked.length != 3) break;
+ final Disk disk = mDisks.get(cooked[1]);
+ if (disk != null) {
+ disk.label = cooked[2];
+ }
+ break;
+ }
+ case VoldResponseCode.DISK_VOLUME_CREATED: {
+ if (cooked.length != 3) break;
+ final Disk disk = mDisks.get(cooked[1]);
+ final Volume vol = mVolumes.get(cooked[2]);
+ if (disk != null && vol != null) {
+ disk.volumes.add(vol);
+ }
+ break;
+ }
+ case VoldResponseCode.DISK_DESTROYED: {
+ if (cooked.length != 2) break;
+ mDisks.remove(cooked[1]);
+ break;
+ }
- if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
- updatePublicVolumeState(volume, Environment.MEDIA_REMOVED);
- action = Intent.ACTION_MEDIA_REMOVED;
- } else if (code == VoldResponseCode.VolumeBadRemoval) {
- if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
- /* Send the media unmounted event first */
- updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
- sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);
+ case VoldResponseCode.VOLUME_CREATED: {
+ if (cooked.length != 3) break;
+ final String id = cooked[1];
+ final int type = Integer.parseInt(cooked[2]);
+ final Volume vol = new Volume(id, type);
+ mVolumes.put(id, vol);
+ onVolumeCreatedLocked(vol);
+ break;
+ }
+ case VoldResponseCode.VOLUME_STATE_CHANGED: {
+ if (cooked.length != 3) break;
+ final Volume vol = mVolumes.get(cooked[1]);
+ if (vol != null) {
+ final int oldState = vol.state;
+ final int newState = Integer.parseInt(cooked[2]);
+ vol.state = newState;
+ onVolumeStateChangedLocked(vol, oldState, newState);
+ }
+ break;
+ }
+ case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
+ if (cooked.length != 3) break;
+ final Volume vol = mVolumes.get(cooked[1]);
+ if (vol != null) {
+ vol.fsType = cooked[2];
+ }
+ break;
+ }
+ case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
+ if (cooked.length != 3) break;
+ final Volume vol = mVolumes.get(cooked[1]);
+ if (vol != null) {
+ vol.fsUuid = cooked[2];
+ }
+ break;
+ }
+ case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
+ if (cooked.length != 3) break;
+ final Volume vol = mVolumes.get(cooked[1]);
+ if (vol != null) {
+ vol.fsLabel = cooked[2];
+ }
+ break;
+ }
+ case VoldResponseCode.VOLUME_PATH_CHANGED: {
+ if (cooked.length != 3) break;
+ final Volume vol = mVolumes.get(cooked[1]);
+ if (vol != null) {
+ vol.path = cooked[2];
+ }
+ break;
+ }
+ case VoldResponseCode.VOLUME_DESTROYED: {
+ if (cooked.length != 2) break;
+ mVolumes.remove(cooked[1]);
+ break;
+ }
- if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
- updatePublicVolumeState(volume, Environment.MEDIA_BAD_REMOVAL);
- action = Intent.ACTION_MEDIA_BAD_REMOVAL;
- } else if (code == VoldResponseCode.FstrimCompleted) {
+ case VoldResponseCode.FstrimCompleted: {
EventLogTags.writeFstrimFinish(SystemClock.elapsedRealtime());
- } else {
- Slog.e(TAG, String.format("Unknown code {%d}", code));
+ break;
}
-
- if (action != null) {
- sendStorageIntent(action, volume, UserHandle.ALL);
+ default: {
+ Slog.d(TAG, "Unhandled vold event " + code);
}
- } else {
- return false;
}
return true;
}
- private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
- final StorageVolume volume;
- final String state;
- synchronized (mVolumesLock) {
- volume = mVolumesByPath.get(path);
- state = getVolumeState(path);
- }
+ private void onVolumeCreatedLocked(Volume vol) {
+ final boolean primaryPhysical = SystemProperties.getBoolean(PROP_PRIMARY_PHYSICAL, false);
+ if (vol.type == Volume.TYPE_EMULATED && !primaryPhysical) {
+ vol.flags |= Volume.FLAG_PRIMARY;
+ vol.flags |= Volume.FLAG_VISIBLE;
+ mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
- if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state);
-
- String action = null;
-
- if (oldState == VolumeState.Shared && newState != oldState) {
- if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");
- sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL);
- }
-
- if (newState == VolumeState.Init) {
- } else if (newState == VolumeState.NoMedia) {
- // NoMedia is handled via Disk Remove events
- } else if (newState == VolumeState.Idle) {
- /*
- * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
- * if we're in the process of enabling UMS
- */
- if (!state.equals(
- Environment.MEDIA_BAD_REMOVAL) && !state.equals(
- Environment.MEDIA_NOFS) && !state.equals(
- Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
- if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
- updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
- action = Intent.ACTION_MEDIA_UNMOUNTED;
+ } else if (vol.type == Volume.TYPE_PUBLIC) {
+ if (primaryPhysical) {
+ vol.flags |= Volume.FLAG_PRIMARY;
}
- } else if (newState == VolumeState.Pending) {
- } else if (newState == VolumeState.Checking) {
- if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");
- updatePublicVolumeState(volume, Environment.MEDIA_CHECKING);
- action = Intent.ACTION_MEDIA_CHECKING;
- } else if (newState == VolumeState.Mounted) {
- if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
- updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
- action = Intent.ACTION_MEDIA_MOUNTED;
- } else if (newState == VolumeState.Unmounting) {
- action = Intent.ACTION_MEDIA_EJECT;
- } else if (newState == VolumeState.Formatting) {
- } else if (newState == VolumeState.Shared) {
- if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");
- /* Send the media unmounted event first */
- updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
- sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);
+ vol.flags |= Volume.FLAG_VISIBLE;
+ vol.userId = UserHandle.USER_OWNER;
+ mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
- if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");
- updatePublicVolumeState(volume, Environment.MEDIA_SHARED);
- action = Intent.ACTION_MEDIA_SHARED;
- if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
- } else if (newState == VolumeState.SharedMnt) {
- Slog.e(TAG, "Live shared mounts not supported yet!");
- return;
} else {
- Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");
- }
-
- if (action != null) {
- sendStorageIntent(action, volume, UserHandle.ALL);
+ Slog.d(TAG, "Skipping automatic mounting of " + vol);
}
}
- private int doMountVolume(String path) {
- int rc = StorageResultCode.OperationSucceeded;
-
- final StorageVolume volume;
- synchronized (mVolumesLock) {
- volume = mVolumesByPath.get(path);
+ private void onVolumeStateChangedLocked(Volume vol, int oldState, int newState) {
+ // Kick state changed event towards all started users. Any users
+ // started after this point will trigger additional
+ // user-specific broadcasts.
+ for (int userId : mStartedUsers) {
+ if (vol.isVisibleToUser(userId)) {
+ final StorageVolume userVol = vol.buildVolumeForUser(userId);
+ mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
+ }
}
- if (!volume.isEmulated() && hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA)) {
- Slog.w(TAG, "User has restriction DISALLOW_MOUNT_PHYSICAL_MEDIA; cannot mount volume.");
- return StorageResultCode.OperationFailedInternalError;
- }
+ // Tell PackageManager about changes to primary volume state, but only
+ // when not emulated.
+ if (vol.isPrimary() && vol.type == Volume.TYPE_PUBLIC) {
+ if (vol.state == Volume.STATE_MOUNTED) {
+ mPms.updateExternalMediaStatus(true, false);
- if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
- try {
- mConnector.execute("volume", "mount", path);
- } catch (NativeDaemonConnectorException e) {
- /*
- * Mount failed for some reason
- */
- String action = null;
- int code = e.getCode();
- if (code == VoldResponseCode.OpFailedNoMedia) {
+ } else if (vol.state == Volume.STATE_UNMOUNTING) {
+ mPms.updateExternalMediaStatus(false, false);
+
+ // TODO: this should eventually be handled by new ObbVolume state changes
/*
- * Attempt to mount but no media inserted
+ * Some OBBs might have been unmounted when this volume was
+ * unmounted, so send a message to the handler to let it know to
+ * remove those from the list of mounted OBBS.
*/
- rc = StorageResultCode.OperationFailedNoMedia;
- } else if (code == VoldResponseCode.OpFailedMediaBlank) {
- if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
- /*
- * Media is blank or does not contain a supported filesystem
- */
- updatePublicVolumeState(volume, Environment.MEDIA_NOFS);
- action = Intent.ACTION_MEDIA_NOFS;
- rc = StorageResultCode.OperationFailedMediaBlank;
- } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
- if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");
- /*
- * Volume consistency check failed
- */
- updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTABLE);
- action = Intent.ACTION_MEDIA_UNMOUNTABLE;
- rc = StorageResultCode.OperationFailedMediaCorrupt;
- } else {
- rc = StorageResultCode.OperationFailedInternalError;
- }
-
- /*
- * Send broadcast intent (if required for the failure)
- */
- if (action != null) {
- sendStorageIntent(action, volume, UserHandle.ALL);
+ mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
+ OBB_FLUSH_MOUNT_STATE, vol.path));
}
}
- return rc;
- }
+ final String oldEnvState = sStateToEnvironment.get(oldState);
+ final String newEnvState = sStateToEnvironment.get(newState);
- /*
- * If force is not set, we do not unmount if there are
- * processes holding references to the volume about to be unmounted.
- * If force is set, all the processes holding references need to be
- * killed via the ActivityManager before actually unmounting the volume.
- * This might even take a while and might be retried after timed delays
- * to make sure we dont end up in an instable state and kill some core
- * processes.
- * If removeEncryption is set, force is implied, and the system will remove any encryption
- * mapping set on the volume when unmounting.
- */
- private int doUnmountVolume(String path, boolean force, boolean removeEncryption) {
- if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
- return VoldResponseCode.OpFailedVolNotMounted;
- }
-
- /*
- * Force a GC to make sure AssetManagers in other threads of the
- * system_server are cleaned up. We have to do this since AssetManager
- * instances are kept as a WeakReference and it's possible we have files
- * open on the external storage.
- */
- Runtime.getRuntime().gc();
-
- // Redundant probably. But no harm in updating state again.
- mPms.updateExternalMediaStatus(false, false);
- try {
- final Command cmd = new Command("volume", "unmount", path);
- if (removeEncryption) {
- cmd.appendArg("force_and_revert");
- } else if (force) {
- cmd.appendArg("force");
- }
- mConnector.execute(cmd);
- // We unmounted the volume. None of the asec containers are available now.
- synchronized (mAsecMountSet) {
- mAsecMountSet.clear();
- }
- return StorageResultCode.OperationSucceeded;
- } catch (NativeDaemonConnectorException e) {
- // Don't worry about mismatch in PackageManager since the
- // call back will handle the status changes any way.
- int code = e.getCode();
- if (code == VoldResponseCode.OpFailedVolNotMounted) {
- return StorageResultCode.OperationFailedStorageNotMounted;
- } else if (code == VoldResponseCode.OpFailedStorageBusy) {
- return StorageResultCode.OperationFailedStorageBusy;
- } else {
- return StorageResultCode.OperationFailedInternalError;
- }
- }
- }
-
- private int doFormatVolume(String path) {
- try {
- mConnector.execute("volume", "format", path);
- return StorageResultCode.OperationSucceeded;
- } catch (NativeDaemonConnectorException e) {
- int code = e.getCode();
- if (code == VoldResponseCode.OpFailedNoMedia) {
- return StorageResultCode.OperationFailedNoMedia;
- } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
- return StorageResultCode.OperationFailedMediaCorrupt;
- } else {
- return StorageResultCode.OperationFailedInternalError;
- }
- }
- }
-
- private boolean doGetVolumeShared(String path, String method) {
- final NativeDaemonEvent event;
- try {
- event = mConnector.execute("volume", "shared", path, method);
- } catch (NativeDaemonConnectorException ex) {
- Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
- return false;
- }
-
- if (event.getCode() == VoldResponseCode.ShareEnabledResult) {
- return event.getMessage().endsWith("enabled");
- } else {
- return false;
- }
- }
-
- private void notifyShareAvailabilityChange(final boolean avail) {
synchronized (mListeners) {
- mUmsAvailable = avail;
for (int i = mListeners.size() -1; i >= 0; i--) {
MountServiceBinderListener bl = mListeners.get(i);
try {
- bl.mListener.onUsbMassStorageConnectionChanged(avail);
+ bl.mListener.onStorageStateChanged(vol.path, oldEnvState, newEnvState);
} catch (RemoteException rex) {
Slog.e(TAG, "Listener dead");
mListeners.remove(i);
@@ -1275,221 +1077,19 @@
}
}
}
-
- if (mSystemReady == true) {
- sendUmsIntent(avail);
- } else {
- mSendUmsConnectedOnBoot = avail;
- }
-
- final StorageVolume primary = getPrimaryPhysicalVolume();
- if (avail == false && primary != null
- && Environment.MEDIA_SHARED.equals(getVolumeState(primary.getPath()))) {
- final String path = primary.getPath();
- /*
- * USB mass storage disconnected while enabled
- */
- new Thread("MountService#AvailabilityChange") {
- @Override
- public void run() {
- try {
- int rc;
- Slog.w(TAG, "Disabling UMS after cable disconnect");
- doShareUnshareVolume(path, "ums", false);
- if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
- Slog.e(TAG, String.format(
- "Failed to remount {%s} on UMS enabled-disconnect (%d)",
- path, rc));
- }
- } catch (Exception ex) {
- Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex);
- }
- }
- }.start();
- }
}
- private void sendStorageIntent(String action, StorageVolume volume, UserHandle user) {
- final Intent intent = new Intent(action, Uri.parse("file://" + volume.getPath()));
- intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- Slog.d(TAG, "sendStorageIntent " + intent + " to " + user);
- mContext.sendBroadcastAsUser(intent, user);
+ private void enforcePermission(String perm) {
+ mContext.enforceCallingOrSelfPermission(perm, perm);
}
- private void sendUmsIntent(boolean c) {
- mContext.sendBroadcastAsUser(
- new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)),
- UserHandle.ALL);
- }
-
- private void validatePermission(String perm) {
- if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(String.format("Requires %s permission", perm));
- }
- }
-
- private boolean hasUserRestriction(String restriction) {
+ private void enforceUserRestriction(String restriction) {
UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- return um.hasUserRestriction(restriction, Binder.getCallingUserHandle());
- }
-
- private void validateUserRestriction(String restriction) {
- if (hasUserRestriction(restriction)) {
+ if (um.hasUserRestriction(restriction, Binder.getCallingUserHandle())) {
throw new SecurityException("User has restriction " + restriction);
}
}
- // Storage list XML tags
- private static final String TAG_STORAGE_LIST = "StorageList";
- private static final String TAG_STORAGE = "storage";
-
- private void readStorageListLocked() {
- mVolumes.clear();
- mVolumeStates.clear();
-
- Resources resources = mContext.getResources();
-
- int id = com.android.internal.R.xml.storage_list;
- XmlResourceParser parser = resources.getXml(id);
- AttributeSet attrs = Xml.asAttributeSet(parser);
-
- try {
- XmlUtils.beginDocument(parser, TAG_STORAGE_LIST);
- while (true) {
- XmlUtils.nextElement(parser);
-
- String element = parser.getName();
- if (element == null) break;
-
- if (TAG_STORAGE.equals(element)) {
- TypedArray a = resources.obtainAttributes(attrs,
- com.android.internal.R.styleable.Storage);
-
- String path = a.getString(
- com.android.internal.R.styleable.Storage_mountPoint);
- int descriptionId = a.getResourceId(
- com.android.internal.R.styleable.Storage_storageDescription, -1);
- CharSequence description = a.getText(
- com.android.internal.R.styleable.Storage_storageDescription);
- boolean primary = a.getBoolean(
- com.android.internal.R.styleable.Storage_primary, false);
- boolean removable = a.getBoolean(
- com.android.internal.R.styleable.Storage_removable, false);
- boolean emulated = a.getBoolean(
- com.android.internal.R.styleable.Storage_emulated, false);
- int mtpReserve = a.getInt(
- com.android.internal.R.styleable.Storage_mtpReserve, 0);
- boolean allowMassStorage = a.getBoolean(
- com.android.internal.R.styleable.Storage_allowMassStorage, false);
- // resource parser does not support longs, so XML value is in megabytes
- long maxFileSize = a.getInt(
- com.android.internal.R.styleable.Storage_maxFileSize, 0) * 1024L * 1024L;
-
- Slog.d(TAG, "got storage path: " + path + " description: " + description +
- " primary: " + primary + " removable: " + removable +
- " emulated: " + emulated + " mtpReserve: " + mtpReserve +
- " allowMassStorage: " + allowMassStorage +
- " maxFileSize: " + maxFileSize);
-
- if (emulated) {
- // For devices with emulated storage, we create separate
- // volumes for each known user.
- mEmulatedTemplate = new StorageVolume(null, descriptionId, true, false,
- true, mtpReserve, false, maxFileSize, null);
-
- final UserManagerService userManager = UserManagerService.getInstance();
- for (UserInfo user : userManager.getUsers(false)) {
- createEmulatedVolumeForUserLocked(user.getUserHandle());
- }
-
- } else {
- if (path == null || description == null) {
- Slog.e(TAG, "Missing storage path or description in readStorageList");
- } else {
- final StorageVolume volume = new StorageVolume(new File(path),
- descriptionId, primary, removable, emulated, mtpReserve,
- allowMassStorage, maxFileSize, null);
- addVolumeLocked(volume);
-
- // Until we hear otherwise, treat as unmounted
- mVolumeStates.put(volume.getPath(), Environment.MEDIA_UNMOUNTED);
- volume.setState(Environment.MEDIA_UNMOUNTED);
- }
- }
-
- a.recycle();
- }
- }
- } catch (XmlPullParserException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- // Compute storage ID for each physical volume; emulated storage is
- // always 0 when defined.
- int index = isExternalStorageEmulated() ? 1 : 0;
- for (StorageVolume volume : mVolumes) {
- if (!volume.isEmulated()) {
- volume.setStorageId(index++);
- }
- }
- parser.close();
- }
- }
-
- /**
- * Create and add new {@link StorageVolume} for given {@link UserHandle}
- * using {@link #mEmulatedTemplate} as template.
- */
- private void createEmulatedVolumeForUserLocked(UserHandle user) {
- if (mEmulatedTemplate == null) {
- throw new IllegalStateException("Missing emulated volume multi-user template");
- }
-
- final UserEnvironment userEnv = new UserEnvironment(user.getIdentifier());
- final File path = userEnv.getExternalStorageDirectory();
- final StorageVolume volume = StorageVolume.fromTemplate(mEmulatedTemplate, path, user);
- volume.setStorageId(0);
- addVolumeLocked(volume);
-
- if (mSystemReady) {
- updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
- } else {
- // Place stub status for early callers to find
- mVolumeStates.put(volume.getPath(), Environment.MEDIA_MOUNTED);
- volume.setState(Environment.MEDIA_MOUNTED);
- }
- }
-
- private void addVolumeLocked(StorageVolume volume) {
- Slog.d(TAG, "addVolumeLocked() " + volume);
- mVolumes.add(volume);
- final StorageVolume existing = mVolumesByPath.put(volume.getPath(), volume);
- if (existing != null) {
- throw new IllegalStateException(
- "Volume at " + volume.getPath() + " already exists: " + existing);
- }
- }
-
- private void removeVolumeLocked(StorageVolume volume) {
- Slog.d(TAG, "removeVolumeLocked() " + volume);
- mVolumes.remove(volume);
- mVolumesByPath.remove(volume.getPath());
- mVolumeStates.remove(volume.getPath());
- }
-
- private StorageVolume getPrimaryPhysicalVolume() {
- synchronized (mVolumesLock) {
- for (StorageVolume volume : mVolumes) {
- if (volume.isPrimary() && !volume.isEmulated()) {
- return volume;
- }
- }
- }
- return null;
- }
-
/**
* Constructs a new MountService instance
*
@@ -1500,10 +1100,6 @@
mContext = context;
- synchronized (mVolumesLock) {
- readStorageListLocked();
- }
-
// XXX: This will go away soon in favor of IMountServiceObserver
mPms = (PackageManagerService) ServiceManager.getService("package");
@@ -1511,19 +1107,6 @@
hthread.start();
mHandler = new MountServiceHandler(hthread.getLooper());
- // Watch for user changes
- final IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(Intent.ACTION_USER_ADDED);
- userFilter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
-
- // Watch for USB changes on primary volume
- final StorageVolume primary = getPrimaryPhysicalVolume();
- if (primary != null && primary.allowMassStorage()) {
- mContext.registerReceiver(
- mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler);
- }
-
// Add OBB Action Handler to MountService thread.
mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
@@ -1550,6 +1133,7 @@
*/
mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
null);
+ mConnector.setDebug(true);
Thread thread = new Thread(mConnector, VOLD_TAG);
thread.start();
@@ -1593,201 +1177,118 @@
}
}
+ @Override
public void shutdown(final IMountShutdownObserver observer) {
- validatePermission(android.Manifest.permission.SHUTDOWN);
+ enforcePermission(android.Manifest.permission.SHUTDOWN);
Slog.i(TAG, "Shutting down");
- synchronized (mVolumesLock) {
- // Get all volumes to be unmounted.
- MountShutdownLatch mountShutdownLatch = new MountShutdownLatch(observer,
- mVolumeStates.size());
-
- for (String path : mVolumeStates.keySet()) {
- String state = mVolumeStates.get(path);
-
- if (state.equals(Environment.MEDIA_SHARED)) {
- /*
- * If the media is currently shared, unshare it.
- * XXX: This is still dangerous!. We should not
- * be rebooting at *all* if UMS is enabled, since
- * the UMS host could have dirty FAT cache entries
- * yet to flush.
- */
- setUsbMassStorageEnabled(false);
- } else if (state.equals(Environment.MEDIA_CHECKING)) {
- /*
- * If the media is being checked, then we need to wait for
- * it to complete before being able to proceed.
- */
- // XXX: @hackbod - Should we disable the ANR timer here?
- int retries = 30;
- while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException iex) {
- Slog.e(TAG, "Interrupted while waiting for media", iex);
- break;
- }
- state = Environment.getExternalStorageState();
- }
- if (retries == 0) {
- Slog.e(TAG, "Timed out waiting for media to check");
- }
- }
-
- if (state.equals(Environment.MEDIA_MOUNTED)) {
- // Post a unmount message.
- ShutdownCallBack ucb = new ShutdownCallBack(path, mountShutdownLatch);
- mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
- } else if (observer != null) {
- /*
- * Count down, since nothing will be done. The observer will be
- * notified when we are done so shutdown sequence can continue.
- */
- mountShutdownLatch.countDown();
- Slog.i(TAG, "Unmount completed: " + path +
- ", result code: " + StorageResultCode.OperationSucceeded);
- }
- }
- }
+ mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
}
- private boolean getUmsEnabling() {
- synchronized (mListeners) {
- return mUmsEnabling;
- }
- }
-
- private void setUmsEnabling(boolean enable) {
- synchronized (mListeners) {
- mUmsEnabling = enable;
- }
- }
-
+ @Override
+ @Deprecated
public boolean isUsbMassStorageConnected() {
- waitForReady();
-
- if (getUmsEnabling()) {
- return true;
- }
- synchronized (mListeners) {
- return mUmsAvailable;
- }
+ return false;
}
+ @Override
+ @Deprecated
public void setUsbMassStorageEnabled(boolean enable) {
- waitForReady();
- validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
- validateUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
-
- final StorageVolume primary = getPrimaryPhysicalVolume();
- if (primary == null) return;
-
- // TODO: Add support for multiple share methods
-
- /*
- * If the volume is mounted and we're enabling then unmount it
- */
- String path = primary.getPath();
- String vs = getVolumeState(path);
- String method = "ums";
- if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
- // Override for isUsbMassStorageEnabled()
- setUmsEnabling(enable);
- UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
- mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
- // Clear override
- setUmsEnabling(false);
- }
- /*
- * If we disabled UMS then mount the volume
- */
- if (!enable) {
- doShareUnshareVolume(path, method, enable);
- if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
- Slog.e(TAG, "Failed to remount " + path +
- " after disabling share method " + method);
- /*
- * Even though the mount failed, the unshare didn't so don't indicate an error.
- * The mountVolume() call will have set the storage state and sent the necessary
- * broadcasts.
- */
- }
- }
+ throw new UnsupportedOperationException();
}
+ @Override
+ @Deprecated
public boolean isUsbMassStorageEnabled() {
- waitForReady();
-
- final StorageVolume primary = getPrimaryPhysicalVolume();
- if (primary != null) {
- return doGetVolumeShared(primary.getPath(), "ums");
- } else {
- return false;
- }
+ return false;
}
/**
* @return state of the volume at the specified mount point
*/
+ @Override
+ @Deprecated
public String getVolumeState(String mountPoint) {
- synchronized (mVolumesLock) {
- String state = mVolumeStates.get(mountPoint);
- if (state == null) {
- Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
- if (SystemProperties.get("vold.encrypt_progress").length() != 0) {
- state = Environment.MEDIA_REMOVED;
- } else {
- throw new IllegalArgumentException();
- }
- }
+ // TODO: pretend that we're unmounted when encrypting?
+ // SystemProperties.get("vold.encrypt_progress")
- return state;
- }
+ final Volume vol = findVolumeByLegacyPath(mountPoint);
+ return sStateToEnvironment.get(vol.state);
}
@Override
public boolean isExternalStorageEmulated() {
- return mEmulatedTemplate != null;
+ return Environment.isExternalStorageEmulated();
}
+ @Override
public int mountVolume(String path) {
- validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
- return doMountVolume(path);
+
+ final Volume vol = findVolumeByLegacyPath(path);
+ if (vol != null) {
+ if (vol.type == Volume.TYPE_PUBLIC || vol.type == Volume.TYPE_PRIVATE) {
+ enforceUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
+ }
+ try {
+ vol.mount();
+ return 0;
+ } catch (NativeDaemonConnectorException ignored) {
+ }
+ } else {
+ Slog.w(TAG, "Unknown volume for path " + path);
+ }
+ return -1;
}
+ @Override
public void unmountVolume(String path, boolean force, boolean removeEncryption) {
- validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
- String volState = getVolumeState(path);
- if (DEBUG_UNMOUNT) {
- Slog.i(TAG, "Unmounting " + path
- + " force = " + force
- + " removeEncryption = " + removeEncryption);
+ final Volume vol = findVolumeByLegacyPath(path);
+ if (vol != null) {
+ // TODO: expand PMS to know about multiple volumes
+ if (vol.isPrimary()) {
+ synchronized (mUnmountLock) {
+ mUnmountSignal = new CountDownLatch(1);
+ mPms.updateExternalMediaStatus(false, true);
+ waitForLatch(mUnmountSignal, "mUnmountSignal");
+ mUnmountSignal = null;
+ }
+ }
+
+ try {
+ vol.unmount();
+ } catch (NativeDaemonConnectorException ignored) {
+ }
+ } else {
+ Slog.w(TAG, "Unknown volume for path " + path);
}
- if (Environment.MEDIA_UNMOUNTED.equals(volState) ||
- Environment.MEDIA_REMOVED.equals(volState) ||
- Environment.MEDIA_SHARED.equals(volState) ||
- Environment.MEDIA_UNMOUNTABLE.equals(volState)) {
- // Media already unmounted or cannot be unmounted.
- // TODO return valid return code when adding observer call back.
- return;
- }
- UnmountCallBack ucb = new UnmountCallBack(path, force, removeEncryption);
- mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
}
+ @Override
public int formatVolume(String path) {
- validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+ enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
waitForReady();
- return doFormatVolume(path);
+ final Volume vol = findVolumeByLegacyPath(path);
+ if (vol != null) {
+ try {
+ vol.format();
+ return 0;
+ } catch (NativeDaemonConnectorException ignored) {
+ }
+ } else {
+ Slog.w(TAG, "Unknown volume for path " + path);
+ }
+ return -1;
}
+ @Override
public int[] getStorageUsers(String path) {
- validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
try {
final String[] r = NativeDaemonEvent.filterMessageList(
@@ -1813,22 +1314,20 @@
}
private void warnOnNotMounted() {
- final StorageVolume primary = getPrimaryPhysicalVolume();
- if (primary != null) {
- boolean mounted = false;
- try {
- mounted = Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath()));
- } catch (IllegalArgumentException e) {
- }
-
- if (!mounted) {
- Slog.w(TAG, "getSecureContainerList() called when storage not mounted");
+ synchronized (mLock) {
+ for (Volume vol : mVolumes.values()) {
+ if (vol.isPrimary() && vol.state == Volume.STATE_MOUNTED) {
+ // Cool beans, we have a mounted primary volume
+ return;
+ }
}
}
+
+ Slog.w(TAG, "No primary storage mounted!");
}
public String[] getSecureContainerList() {
- validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ enforcePermission(android.Manifest.permission.ASEC_ACCESS);
waitForReady();
warnOnNotMounted();
@@ -1842,7 +1341,7 @@
public int createSecureContainer(String id, int sizeMb, String fstype, String key,
int ownerUid, boolean external) {
- validatePermission(android.Manifest.permission.ASEC_CREATE);
+ enforcePermission(android.Manifest.permission.ASEC_CREATE);
waitForReady();
warnOnNotMounted();
@@ -1864,7 +1363,7 @@
@Override
public int resizeSecureContainer(String id, int sizeMb, String key) {
- validatePermission(android.Manifest.permission.ASEC_CREATE);
+ enforcePermission(android.Manifest.permission.ASEC_CREATE);
waitForReady();
warnOnNotMounted();
@@ -1878,7 +1377,7 @@
}
public int finalizeSecureContainer(String id) {
- validatePermission(android.Manifest.permission.ASEC_CREATE);
+ enforcePermission(android.Manifest.permission.ASEC_CREATE);
warnOnNotMounted();
int rc = StorageResultCode.OperationSucceeded;
@@ -1895,7 +1394,7 @@
}
public int fixPermissionsSecureContainer(String id, int gid, String filename) {
- validatePermission(android.Manifest.permission.ASEC_CREATE);
+ enforcePermission(android.Manifest.permission.ASEC_CREATE);
warnOnNotMounted();
int rc = StorageResultCode.OperationSucceeded;
@@ -1912,7 +1411,7 @@
}
public int destroySecureContainer(String id, boolean force) {
- validatePermission(android.Manifest.permission.ASEC_DESTROY);
+ enforcePermission(android.Manifest.permission.ASEC_DESTROY);
waitForReady();
warnOnNotMounted();
@@ -1952,7 +1451,7 @@
}
public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
- validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
+ enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
waitForReady();
warnOnNotMounted();
@@ -1982,7 +1481,7 @@
}
public int unmountSecureContainer(String id, boolean force) {
- validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
+ enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
waitForReady();
warnOnNotMounted();
@@ -2025,7 +1524,7 @@
}
public boolean isSecureContainerMounted(String id) {
- validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ enforcePermission(android.Manifest.permission.ASEC_ACCESS);
waitForReady();
warnOnNotMounted();
@@ -2035,7 +1534,7 @@
}
public int renameSecureContainer(String oldId, String newId) {
- validatePermission(android.Manifest.permission.ASEC_RENAME);
+ enforcePermission(android.Manifest.permission.ASEC_RENAME);
waitForReady();
warnOnNotMounted();
@@ -2060,7 +1559,7 @@
}
public String getSecureContainerPath(String id) {
- validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ enforcePermission(android.Manifest.permission.ASEC_ACCESS);
waitForReady();
warnOnNotMounted();
@@ -2081,7 +1580,7 @@
}
public String getSecureContainerFilesystemPath(String id) {
- validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ enforcePermission(android.Manifest.permission.ASEC_ACCESS);
waitForReady();
warnOnNotMounted();
@@ -2101,8 +1600,13 @@
}
}
+ @Override
public void finishMediaUpdate() {
- mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
+ if (mUnmountSignal != null) {
+ mUnmountSignal.countDown();
+ } else {
+ Slog.w(TAG, "Odd, nobody asked to unmount?");
+ }
}
private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
@@ -2477,109 +1981,84 @@
Context.APP_OPS_SERVICE);
appOps.checkPackage(Binder.getCallingUid(), callingPkg);
+ File appFile = null;
try {
- appPath = new File(appPath).getCanonicalPath();
+ appFile = new File(appPath).getCanonicalFile();
} catch (IOException e) {
Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
return -1;
}
- if (!appPath.endsWith("/")) {
- appPath = appPath + "/";
- }
-
// Try translating the app path into a vold path, but require that it
// belong to the calling package.
- String voldPath = maybeTranslatePathForVold(appPath,
- userEnv.buildExternalStorageAppDataDirs(callingPkg),
- userEnv.buildExternalStorageAppDataDirsForVold(callingPkg));
- if (voldPath != null) {
+ if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
+ FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
+ FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
+ appPath = appFile.getAbsolutePath();
+ if (!appPath.endsWith("/")) {
+ appPath = appPath + "/";
+ }
+
try {
- mConnector.execute("volume", "mkdirs", voldPath);
+ mConnector.execute("volume", "mkdirs", appPath);
return 0;
} catch (NativeDaemonConnectorException e) {
return e.getCode();
}
}
- voldPath = maybeTranslatePathForVold(appPath,
- userEnv.buildExternalStorageAppObbDirs(callingPkg),
- userEnv.buildExternalStorageAppObbDirsForVold(callingPkg));
- if (voldPath != null) {
- try {
- mConnector.execute("volume", "mkdirs", voldPath);
- return 0;
- } catch (NativeDaemonConnectorException e) {
- return e.getCode();
- }
- }
-
- voldPath = maybeTranslatePathForVold(appPath,
- userEnv.buildExternalStorageAppMediaDirs(callingPkg),
- userEnv.buildExternalStorageAppMediaDirsForVold(callingPkg));
- if (voldPath != null) {
- try {
- mConnector.execute("volume", "mkdirs", voldPath);
- return 0;
- } catch (NativeDaemonConnectorException e) {
- return e.getCode();
- }
- }
-
- throw new SecurityException("Invalid mkdirs path: " + appPath);
- }
-
- /**
- * Translate the given path from an app-visible path to a vold-visible path,
- * but only if it's under the given whitelisted paths.
- *
- * @param path a canonicalized app-visible path.
- * @param appPaths list of app-visible paths that are allowed.
- * @param voldPaths list of vold-visible paths directly corresponding to the
- * allowed app-visible paths argument.
- * @return a vold-visible path representing the original path, or
- * {@code null} if the given path didn't have an app-to-vold
- * mapping.
- */
- @VisibleForTesting
- public static String maybeTranslatePathForVold(
- String path, File[] appPaths, File[] voldPaths) {
- if (appPaths.length != voldPaths.length) {
- throw new IllegalStateException("Paths must be 1:1 mapping");
- }
-
- for (int i = 0; i < appPaths.length; i++) {
- final String appPath = appPaths[i].getAbsolutePath() + "/";
- if (path.startsWith(appPath)) {
- path = new File(voldPaths[i], path.substring(appPath.length()))
- .getAbsolutePath();
- if (!path.endsWith("/")) {
- path = path + "/";
- }
- return path;
- }
- }
- return null;
+ throw new SecurityException("Invalid mkdirs path: " + appFile);
}
@Override
- public StorageVolume[] getVolumeList() {
- final int callingUserId = UserHandle.getCallingUserId();
- final boolean accessAll = (mContext.checkPermission(
- android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
- Binder.getCallingPid(), Binder.getCallingUid()) == PERMISSION_GRANTED);
+ public StorageVolume[] getVolumeList(int userId) {
+ if (UserHandle.getCallingUserId() != userId) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE, "getVolumeList");
+ }
- synchronized (mVolumesLock) {
- final ArrayList<StorageVolume> filtered = Lists.newArrayList();
- for (StorageVolume volume : mVolumes) {
- final UserHandle owner = volume.getOwner();
- final boolean ownerMatch = owner == null || owner.getIdentifier() == callingUserId;
- if (accessAll || ownerMatch) {
- filtered.add(volume);
+ final ArrayList<StorageVolume> res = Lists.newArrayList();
+ boolean foundPrimary = false;
+ synchronized (mLock) {
+ for (Volume vol : mVolumes.values()) {
+ if (vol.isVisibleToUser(userId)) {
+ final StorageVolume userVol = vol.buildVolumeForUser(userId);
+ if (vol.isPrimary()) {
+ res.add(0, userVol);
+ foundPrimary = true;
+ } else {
+ res.add(userVol);
+ }
}
}
- return filtered.toArray(new StorageVolume[filtered.size()]);
}
+
+ if (!foundPrimary) {
+ Slog.w(TAG, "No primary storage defined yet; hacking together a stub");
+
+ final boolean primaryPhysical = SystemProperties.getBoolean(
+ PROP_PRIMARY_PHYSICAL, false);
+
+ final String id = "stub_primary";
+ final File path = Environment.getLegacyExternalStorageDirectory();
+ final int descriptionId = android.R.string.unknownName;
+ final boolean primary = true;
+ final boolean removable = primaryPhysical;
+ final boolean emulated = !primaryPhysical;
+ final long mtpReserveSize = 0L;
+ final boolean allowMassStorage = false;
+ final long maxFileSize = 0L;
+ final UserHandle owner = new UserHandle(userId);
+ final String uuid = null;
+ final String userLabel = null;
+ final String state = Environment.MEDIA_REMOVED;
+
+ res.add(0, new StorageVolume(id, MtpStorage.getStorageIdForIndex(0), path,
+ descriptionId, primary, removable, emulated, mtpReserveSize,
+ allowMassStorage, maxFileSize, owner, uuid, userLabel, state));
+ }
+
+ return res.toArray(new StorageVolume[res.size()]);
}
private void addObbStateLocked(ObbState obbState) throws RemoteException {
@@ -3073,21 +2552,13 @@
if (path.startsWith(obbPath)) {
path = path.substring(obbPath.length() + 1);
- if (forVold) {
- return new File(Environment.getEmulatedStorageObbSource(), path).getAbsolutePath();
- } else {
- final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER);
- return new File(ownerEnv.buildExternalStorageAndroidObbDirs()[0], path)
- .getAbsolutePath();
- }
+ final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER);
+ return new File(ownerEnv.buildExternalStorageAndroidObbDirs()[0], path)
+ .getAbsolutePath();
}
// Handle normal external storage paths
- if (forVold) {
- return new File(Environment.getEmulatedStorageSource(userId), path).getAbsolutePath();
- } else {
- return new File(userEnv.getExternalDirsForApp()[0], path).getAbsolutePath();
- }
+ return new File(userEnv.getExternalStorageDirectory(), path).getAbsolutePath();
}
@Override
@@ -3126,15 +2597,20 @@
pw.decreaseIndent();
}
- synchronized (mVolumesLock) {
+ synchronized (mLock) {
pw.println();
- pw.println("mVolumes:");
+ pw.println("Disks:");
pw.increaseIndent();
- for (StorageVolume volume : mVolumes) {
- pw.println(volume);
- pw.increaseIndent();
- pw.println("Current state: " + mVolumeStates.get(volume.getPath()));
- pw.decreaseIndent();
+ for (Disk disk : mDisks.values()) {
+ disk.dump(pw);
+ }
+ pw.decreaseIndent();
+
+ pw.println();
+ pw.println("Volumes:");
+ pw.increaseIndent();
+ for (Volume vol : mVolumes.values()) {
+ vol.dump(pw);
}
pw.decreaseIndent();
}
@@ -3153,6 +2629,7 @@
}
/** {@inheritDoc} */
+ @Override
public void monitor() {
if (mConnector != null) {
mConnector.monitor();
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index d2dfc7b..78c7f38 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -48,8 +48,6 @@
* {@code libsysutils} FrameworkListener protocol.
*/
final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor {
- private static final boolean LOGD = false;
-
private final static boolean VDBG = false;
private final String TAG;
@@ -58,6 +56,8 @@
private OutputStream mOutputStream;
private LocalLog mLocalLog;
+ private volatile boolean mDebug = false;
+
private final ResponseQueue mResponseQueue;
private final PowerManager.WakeLock mWakeLock;
@@ -99,6 +99,14 @@
mLocalLog = new LocalLog(maxLogSize);
}
+ /**
+ * Enable Set debugging mode, which causes messages to also be written to both
+ * {@link Slog} in addition to internal log.
+ */
+ public void setDebug(boolean debug) {
+ mDebug = debug;
+ }
+
@Override
public void run() {
mCallbackHandler = new Handler(mLooper, this);
@@ -513,7 +521,7 @@
}
private void log(String logstring) {
- if (LOGD) Slog.d(TAG, logstring);
+ if (mDebug) Slog.d(TAG, logstring);
mLocalLog.log(logstring);
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a64e6c3..1b32f57 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -109,7 +109,7 @@
private static final int TIMEOUT_DELAY_MS = 1000 * 60;
private static final String DATABASE_NAME = "accounts.db";
- private static final int DATABASE_VERSION = 6;
+ private static final int DATABASE_VERSION = 7;
private final Context mContext;
@@ -131,6 +131,8 @@
private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
private static final String ACCOUNTS_PASSWORD = "password";
private static final String ACCOUNTS_PREVIOUS_NAME = "previous_name";
+ private static final String ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS =
+ "last_password_entry_time_millis_epoch";
private static final String TABLE_AUTHTOKENS = "authtokens";
private static final String AUTHTOKENS_ID = "_id";
@@ -697,7 +699,8 @@
long identityToken = clearCallingIdentity();
try {
new Session(fromAccounts, response, account.type, false,
- false /* stripAuthTokenFromResult */) {
+ false /* stripAuthTokenFromResult */, account.name,
+ false /* authDetailsRequired */) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountCredentialsForClone"
@@ -725,12 +728,43 @@
}
}
+ @Override
+ public boolean accountAuthenticated(final Account account) {
+ if (account == null) {
+ throw new IllegalArgumentException("account is null");
+ }
+ checkAuthenticateAccountsPermission(account);
+
+ final UserAccounts accounts = getUserAccountsForCaller();
+ int userId = Binder.getCallingUserHandle().getIdentifier();
+ if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
+ return false;
+ }
+ synchronized (accounts.cacheLock) {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
+ final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ int i = db.update(
+ TABLE_ACCOUNTS,
+ values,
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[] {
+ account.name, account.type
+ });
+ if (i > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void completeCloningAccount(IAccountManagerResponse response,
final Bundle accountCredentials, final Account account, final UserAccounts targetUser) {
long id = clearCallingIdentity();
try {
new Session(targetUser, response, account.type, false,
- false /* stripAuthTokenFromResult */) {
+ false /* stripAuthTokenFromResult */, account.name,
+ false /* authDetailsRequired */) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAccountCredentialsForClone"
@@ -795,6 +829,7 @@
values.put(ACCOUNTS_NAME, account.name);
values.put(ACCOUNTS_TYPE, account.type);
values.put(ACCOUNTS_PASSWORD, password);
+ values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
@@ -885,7 +920,8 @@
public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
Account account, String[] features) {
super(accounts, response, account.type, false /* expectActivityLaunch */,
- true /* stripAuthTokenFromResult */);
+ true /* stripAuthTokenFromResult */, account.name,
+ false /* authDetailsRequired */);
mFeatures = features;
mAccount = account;
}
@@ -1184,7 +1220,8 @@
public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
Account account, boolean expectActivityLaunch) {
super(accounts, response, account.type, expectActivityLaunch,
- true /* stripAuthTokenFromResult */);
+ true /* stripAuthTokenFromResult */, account.name,
+ false /* authDetailsRequired */);
mAccount = account;
}
@@ -1419,6 +1456,13 @@
try {
final ContentValues values = new ContentValues();
values.put(ACCOUNTS_PASSWORD, password);
+ long time = 0;
+ // Only set current time, if it is a valid password. For clear password case, it
+ // should not be set.
+ if (password != null) {
+ time = System.currentTimeMillis();
+ }
+ values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, time);
final long accountId = getAccountIdLocked(db, account);
if (accountId >= 0) {
final String[] argsAccountId = {String.valueOf(accountId)};
@@ -1547,8 +1591,9 @@
UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
long identityToken = clearCallingIdentity();
try {
- new Session(accounts, response, accountType, false,
- false /* stripAuthTokenFromResult */) {
+ new Session(accounts, response, accountType, false /* expectActivityLaunch */,
+ false /* stripAuthTokenFromResult */, null /* accountName */,
+ false /* authDetailsRequired */) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", getAuthTokenLabel"
@@ -1648,7 +1693,8 @@
}
new Session(accounts, response, account.type, expectActivityLaunch,
- false /* stripAuthTokenFromResult */) {
+ false /* stripAuthTokenFromResult */, account.name,
+ false /* authDetailsRequired */) {
@Override
protected String toDebugString(long now) {
if (loginOptions != null) loginOptions.keySet();
@@ -1842,7 +1888,8 @@
long identityToken = clearCallingIdentity();
try {
new Session(accounts, response, accountType, expectActivityLaunch,
- true /* stripAuthTokenFromResult */) {
+ true /* stripAuthTokenFromResult */, null /* accountName */,
+ false /* authDetailsRequired */) {
@Override
public void run() throws RemoteException {
mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
@@ -1917,7 +1964,8 @@
long identityToken = clearCallingIdentity();
try {
new Session(accounts, response, accountType, expectActivityLaunch,
- true /* stripAuthTokenFromResult */) {
+ true /* stripAuthTokenFromResult */, null /* accountName */,
+ false /* authDetailsRequired */) {
@Override
public void run() throws RemoteException {
mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
@@ -1973,7 +2021,8 @@
long identityToken = clearCallingIdentity();
try {
new Session(accounts, response, account.type, expectActivityLaunch,
- true /* stripAuthTokenFromResult */) {
+ true /* stripAuthTokenFromResult */, account.name,
+ true /* authDetailsRequired */) {
@Override
public void run() throws RemoteException {
mAuthenticator.confirmCredentials(this, account, options);
@@ -2009,7 +2058,8 @@
long identityToken = clearCallingIdentity();
try {
new Session(accounts, response, account.type, expectActivityLaunch,
- true /* stripAuthTokenFromResult */) {
+ true /* stripAuthTokenFromResult */, account.name,
+ false /* authDetailsRequired */) {
@Override
public void run() throws RemoteException {
mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
@@ -2045,7 +2095,8 @@
long identityToken = clearCallingIdentity();
try {
new Session(accounts, response, accountType, expectActivityLaunch,
- true /* stripAuthTokenFromResult */) {
+ true /* stripAuthTokenFromResult */, null /* accountName */,
+ false /* authDetailsRequired */) {
@Override
public void run() throws RemoteException {
mAuthenticator.editProperties(this, mAccountType);
@@ -2071,7 +2122,8 @@
public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
IAccountManagerResponse response, String type, String[] features, int callingUid) {
super(accounts, response, type, false /* expectActivityLaunch */,
- true /* stripAuthTokenFromResult */);
+ true /* stripAuthTokenFromResult */, null /* accountName */,
+ false /* authDetailsRequired */);
mCallingUid = callingUid;
mFeatures = features;
}
@@ -2437,6 +2489,9 @@
final String mAccountType;
final boolean mExpectActivityLaunch;
final long mCreationTime;
+ final String mAccountName;
+ // Indicates if we need to add auth details(like last credential time)
+ final boolean mAuthDetailsRequired;
public int mNumResults = 0;
private int mNumRequestContinued = 0;
@@ -2448,7 +2503,8 @@
protected final UserAccounts mAccounts;
public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
- boolean expectActivityLaunch, boolean stripAuthTokenFromResult) {
+ boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName,
+ boolean authDetailsRequired) {
super();
//if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
@@ -2458,6 +2514,9 @@
mAccountType = accountType;
mExpectActivityLaunch = expectActivityLaunch;
mCreationTime = SystemClock.elapsedRealtime();
+ mAccountName = accountName;
+ mAuthDetailsRequired = authDetailsRequired;
+
synchronized (mSessions) {
mSessions.put(toString(), this);
}
@@ -2592,6 +2651,16 @@
public void onResult(Bundle result) {
mNumResults++;
Intent intent = null;
+ if (result != null && mAuthDetailsRequired) {
+ long lastAuthenticatedTime = DatabaseUtils.longForQuery(
+ mAccounts.openHelper.getReadableDatabase(),
+ "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " from " +
+ TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
+ + ACCOUNTS_TYPE + "=?",
+ new String[]{mAccountName, mAccountType});
+ result.putLong(AccountManager.KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH,
+ lastAuthenticatedTime);
+ }
if (result != null
&& (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
/*
@@ -2798,6 +2867,7 @@
+ ACCOUNTS_TYPE + " TEXT NOT NULL, "
+ ACCOUNTS_PASSWORD + " TEXT, "
+ ACCOUNTS_PREVIOUS_NAME + " TEXT, "
+ + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " INTEGER DEFAULT 0, "
+ "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " ( "
@@ -2833,6 +2903,11 @@
+ "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
}
+ private void addLastSuccessfullAuthenticatedTimeColumn(SQLiteDatabase db) {
+ db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN "
+ + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " DEFAULT 0");
+ }
+
private void addOldAccountNameColumn(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE_ACCOUNTS + " ADD COLUMN " + ACCOUNTS_PREVIOUS_NAME);
}
@@ -2892,6 +2967,11 @@
oldVersion++;
}
+ if (oldVersion == 6) {
+ addLastSuccessfullAuthenticatedTimeColumn(db);
+ oldVersion++;
+ }
+
if (oldVersion != newVersion) {
Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index fd4974e..7a74e45 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -72,7 +72,7 @@
static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
- static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
+ static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
static final String POSTFIX_BACKUP = (APPEND_CATEGORY_NAME) ? "_Backup" : "";
static final String POSTFIX_BROADCAST = (APPEND_CATEGORY_NAME) ? "_Broadcast" : "";
@@ -80,11 +80,29 @@
static final String POSTFIX_CONFIGURATION = (APPEND_CATEGORY_NAME) ? "_Configuration" : "";
static final String POSTFIX_FOCUS = (APPEND_CATEGORY_NAME) ? "_Focus" : "";
static final String POSTFIX_IMMERSIVE = (APPEND_CATEGORY_NAME) ? "_Immersive" : "";
+ static final String POSTFIX_LOCKSCREEN = (APPEND_CATEGORY_NAME) ? "_LOCKSCREEN" : "";
static final String POSTFIX_LRU = (APPEND_CATEGORY_NAME) ? "_LRU" : "";
static final String POSTFIX_MU = "_MU";
static final String POSTFIX_OOM_ADJ = (APPEND_CATEGORY_NAME) ? "_OomAdj" : "";
+ static final String POSTFIX_PAUSE = (APPEND_CATEGORY_NAME) ? "_Pause" : "";
+ static final String POSTFIX_POWER = (APPEND_CATEGORY_NAME) ? "_Power" : "";
+ static final String POSTFIX_PROCESS_OBSERVERS = (APPEND_CATEGORY_NAME)
+ ? "_ProcessObservers" : "";
+ static final String POSTFIX_PROCESSES = (APPEND_CATEGORY_NAME) ? "_Processes" : "";
+ static final String POSTFIX_PROVIDER = (APPEND_CATEGORY_NAME) ? "_Provider" : "";
+ static final String POSTFIX_PSS = (APPEND_CATEGORY_NAME) ? "_Pss" : "";
+ static final String POSTFIX_RESULTS = (APPEND_CATEGORY_NAME) ? "_Results" : "";
+ static final String POSTFIX_RECENTS = (APPEND_CATEGORY_NAME) ? "_Recents" : "";
static final String POSTFIX_SERVICE = (APPEND_CATEGORY_NAME) ? "_Service" : "";
static final String POSTFIX_SERVICE_EXECUTING =
(APPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
+ static final String POSTFIX_STACK = (APPEND_CATEGORY_NAME) ? "_Stack" : "";
+ static final String POSTFIX_SWITCH = (APPEND_CATEGORY_NAME) ? "_Switch" : "";
+ static final String POSTFIX_TASKS = (APPEND_CATEGORY_NAME) ? "_Tasks" : "";
+ static final String POSTFIX_THUMBNAILS = (APPEND_CATEGORY_NAME) ? "_Thumbnails" : "";
+ static final String POSTFIX_TRANSITION = (APPEND_CATEGORY_NAME) ? "_Transition" : "";
+ static final String POSTFIX_URI_PERMISSION = (APPEND_CATEGORY_NAME) ? "_UriPermission" : "";
+ static final String POSTFIX_USER_LEAVING = (APPEND_CATEGORY_NAME) ? "_UserLeaving" : "";
+ static final String POSTFIX_VISIBILITY = (APPEND_CATEGORY_NAME) ? "_Visibility" : "";
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b5e1de9..5858477 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26,12 +26,12 @@
import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
-import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
import android.app.AppOpsManager;
@@ -259,37 +259,30 @@
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
+ private static final String TAG_LOCKSCREEN = TAG + POSTFIX_LOCKSCREEN;
private static final String TAG_LRU = TAG + POSTFIX_LRU;
private static final String TAG_MU = TAG + POSTFIX_MU;
private static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
+ private static final String TAG_POWER = TAG + POSTFIX_POWER;
+ private static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
+ private static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES;
+ private static final String TAG_PROVIDER = TAG + POSTFIX_PROVIDER;
+ private static final String TAG_PSS = TAG + POSTFIX_PSS;
+ private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+ private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
+ private static final String TAG_STACK = TAG + POSTFIX_STACK;
+ private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+ private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
+ private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
- // TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class.
- static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
- static final boolean DEBUG_POWER = DEBUG_ALL || false;
- static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
- static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
- static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
- static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
- static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
- static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
- static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
- static final boolean DEBUG_STACK = DEBUG_ALL || false;
- static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
- static final boolean DEBUG_TASKS = DEBUG_ALL || false;
- static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
- static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
- static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
- static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
- static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
- static final boolean DEBUG_PSS = DEBUG_ALL || false;
- static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
- static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
-
- // Control over CPU and battery monitoring.
- static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
+ /** Control over CPU and battery monitoring */
+ // write battery stats every 30 minutes.
+ static final long BATTERY_STATS_TIME = 30 * 60 * 1000;
static final boolean MONITOR_CPU_USAGE = true;
- static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
- static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
+ // don't sample cpu less than every 5 seconds.
+ static final long MONITOR_CPU_MIN_TIME = 5 * 1000;
+ // wait possibly forever for next cpu sample.
+ static final long MONITOR_CPU_MAX_TIME = 0x0fffffff;
static final boolean MONITOR_THREAD_CPU_USAGE = false;
// The flags that are set for all calls we make to the package manager.
@@ -1847,8 +1840,8 @@
return;
}
- if (DEBUG_PSS) Slog.d(TAG, "Showing dump heap notification from "
- + procName + "/" + uid);
+ if (DEBUG_PSS) Slog.d(TAG_PSS,
+ "Showing dump heap notification from " + procName + "/" + uid);
INotificationManager inm = NotificationManager.getService();
if (inm == null) {
@@ -1946,7 +1939,7 @@
}
memInfo.readMemInfo();
synchronized (ActivityManagerService.this) {
- if (DEBUG_PSS) Slog.d(TAG, "Collected native and kernel memory in "
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Collected native and kernel memory in "
+ (SystemClock.uptimeMillis()-start) + "ms");
final long cachedKb = memInfo.getCachedSizeKb();
final long freeKb = memInfo.getFreeSizeKb();
@@ -1968,8 +1961,9 @@
long lastPssTime;
synchronized (ActivityManagerService.this) {
if (mPendingPssProcesses.size() <= 0) {
- if (mTestPssMode || DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num
- + " processes in " + (SystemClock.uptimeMillis()-start) + "ms");
+ if (mTestPssMode || DEBUG_PSS) Slog.d(TAG_PSS,
+ "Collected PSS of " + num + " processes in "
+ + (SystemClock.uptimeMillis() - start) + "ms");
mPendingPssProcesses.clear();
return;
}
@@ -2528,7 +2522,7 @@
@Override
public void notifyActivityDrawn(IBinder token) {
- if (DEBUG_VISBILITY) Slog.d(TAG, "notifyActivityDrawn: token=" + token);
+ if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, "notifyActivityDrawn: token=" + token);
synchronized (this) {
ActivityRecord r = mStackSupervisor.isInAnyStackLocked(token);
if (r != null) {
@@ -2828,7 +2822,7 @@
} else if (proc != null && !keepIfLarge
&& mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
&& proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
- if (DEBUG_PSS) Slog.d(TAG, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
if (proc.baseProcessTracker != null) {
proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
@@ -2910,7 +2904,7 @@
// object attached to it so we know it couldn't have crashed; and
// (3) There is a pid assigned to it, so it is either starting or
// already running.
- if (DEBUG_PROCESSES) Slog.v(TAG, "startProcess: name=" + processName
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName
+ " app=" + app + " knownToBeDead=" + knownToBeDead
+ " thread=" + (app != null ? app.thread : null)
+ " pid=" + (app != null ? app.pid : -1));
@@ -2918,7 +2912,7 @@
if (!knownToBeDead || app.thread == null) {
// We already have the app running, or are waiting for it to
// come up (we have a pid but not yet its thread), so keep it.
- if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName, info.versionCode, mProcessStats);
checkTime(startTime, "startProcess: done, added package to proc");
@@ -2927,7 +2921,7 @@
// An application record is attached to a previous process,
// clean it up now.
- if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG, "App died: " + app);
+ if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
checkTime(startTime, "startProcess: bad proc running, killing");
Process.killProcessGroup(app.info.uid, app.pid);
handleAppDiedLocked(app, true, true);
@@ -2942,7 +2936,7 @@
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
if (mBadProcesses.get(info.processName, info.uid) != null) {
- if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Bad process: " + info.uid
+ "/" + info.processName);
return null;
}
@@ -2951,7 +2945,7 @@
// crash count so that we won't make it bad until they see at
// least one crash dialog again, and make the process good again
// if it had been bad.
- if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Clearing bad process: " + info.uid
+ "/" + info.processName);
mProcessCrashTimes.remove(info.processName, info.uid);
if (mBadProcesses.get(info.processName, info.uid) != null) {
@@ -2994,7 +2988,8 @@
if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app);
}
- if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
+ "System not ready, putting on hold: " + app);
checkTime(startTime, "startProcess: returning with proc on hold");
return app;
}
@@ -3029,7 +3024,7 @@
app.setPid(0);
}
- if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+ if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
"startProcessLocked removing on hold: " + app);
mProcessesOnHold.remove(app);
@@ -3041,24 +3036,13 @@
int uid = app.uid;
int[] gids = null;
- int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
+ int mountExternal = Zygote.MOUNT_EXTERNAL_DEFAULT;
if (!app.isolated) {
int[] permGids = null;
try {
checkTime(startTime, "startProcess: getting gids from package manager");
permGids = AppGlobals.getPackageManager().getPackageGids(app.info.packageName,
app.userId);
-
- if (Environment.isExternalStorageEmulated()) {
- checkTime(startTime, "startProcess: checking external storage perm");
- if (mContext.getPackageManager().checkPermission(
- android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
- app.info.packageName) == PERMISSION_GRANTED) {
- mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
- } else {
- mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
- }
- }
} catch (RemoteException e) {
Slog.w(TAG, "Unable to retrieve gids", e);
}
@@ -3209,7 +3193,8 @@
}
void updateUsageStats(ActivityRecord component, boolean resumed) {
- if (DEBUG_SWITCH) Slog.d(TAG, "updateUsageStats: comp=" + component + "res=" + resumed);
+ if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
+ "updateUsageStats: comp=" + component + "res=" + resumed);
final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
if (resumed) {
if (mUsageStatsService != null) {
@@ -3427,7 +3412,8 @@
mPendingProcessChanges.toArray(mActiveProcessChanges);
mAvailProcessChanges.addAll(mPendingProcessChanges);
mPendingProcessChanges.clear();
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "*** Delivering " + N + " process changes");
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "*** Delivering " + N + " process changes");
}
int i = mProcessObservers.beginBroadcast();
@@ -3439,15 +3425,16 @@
for (int j=0; j<N; j++) {
ProcessChangeItem item = mActiveProcessChanges[j];
if ((item.changes&ProcessChangeItem.CHANGE_ACTIVITIES) != 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "ACTIVITIES CHANGED pid="
- + item.pid + " uid=" + item.uid + ": "
- + item.foregroundActivities);
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "ACTIVITIES CHANGED pid=" + item.pid + " uid="
+ + item.uid + ": " + item.foregroundActivities);
observer.onForegroundActivitiesChanged(item.pid, item.uid,
item.foregroundActivities);
}
if ((item.changes&ProcessChangeItem.CHANGE_PROCESS_STATE) != 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "PROCSTATE CHANGED pid="
- + item.pid + " uid=" + item.uid + ": " + item.processState);
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "PROCSTATE CHANGED pid=" + item.pid + " uid=" + item.uid
+ + ": " + item.processState);
observer.onProcessStateChanged(item.pid, item.uid, item.processState);
}
}
@@ -4363,7 +4350,7 @@
+ ") has died and restarted (pid " + app.pid + ").");
EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
} else if (DEBUG_PROCESSES) {
- Slog.d(TAG, "Received spurious death notification for thread "
+ Slog.d(TAG_PROCESSES, "Received spurious death notification for thread "
+ thread.asBinder());
}
}
@@ -5398,9 +5385,8 @@
boolean callerWillRestart, boolean allowRestart, String reason) {
final String name = app.processName;
final int uid = app.uid;
- if (DEBUG_PROCESSES) Slog.d(
- TAG, "Force removing proc " + app.toShortString() + " (" + name
- + "/" + uid + ")");
+ if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
+ "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");
mProcessNames.remove(name, uid);
mIsolatedProcesses.remove(app.uid);
@@ -5644,7 +5630,7 @@
// Remove this record from the list of starting applications.
mPersistentStartingProcesses.remove(app);
- if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+ if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
"Attach application locked removing on hold: " + app);
mProcessesOnHold.remove(app);
@@ -5852,7 +5838,7 @@
ArrayList<ProcessRecord> procs =
new ArrayList<ProcessRecord>(mProcessesOnHold);
for (int ip=0; ip<NP; ip++) {
- if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: "
+ if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Starting process on hold: "
+ procs.get(ip));
startProcessLocked(procs.get(ip), "on-hold", null);
}
@@ -5993,7 +5979,7 @@
@Override
public final void activityDestroyed(IBinder token) {
- if (DEBUG_SWITCH) Slog.v(TAG, "ACTIVITY DESTROYED: " + token);
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "ACTIVITY DESTROYED: " + token);
synchronized (this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
@@ -6598,7 +6584,7 @@
*/
private final boolean checkHoldingPermissionsLocked(
IPackageManager pm, ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"checkHoldingPermissionsLocked: uri=" + grantUri + " uid=" + uid);
if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
if (ActivityManager.checkComponentPermission(INTERACT_ACROSS_USERS, uid, -1, true)
@@ -6646,8 +6632,8 @@
if (pp.match(path)) {
if (!readMet) {
final String pprperm = pp.getReadPermission();
- if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for "
- + pprperm + " for " + pp.getPath()
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+ "Checking read perm for " + pprperm + " for " + pp.getPath()
+ ": match=" + pp.match(path)
+ " check=" + pm.checkUidPermission(pprperm, uid));
if (pprperm != null) {
@@ -6661,8 +6647,8 @@
}
if (!writeMet) {
final String ppwperm = pp.getWritePermission();
- if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm "
- + ppwperm + " for " + pp.getPath()
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+ "Checking write perm " + ppwperm + " for " + pp.getPath()
+ ": match=" + pp.match(path)
+ " check=" + pm.checkUidPermission(ppwperm, uid));
if (ppwperm != null) {
@@ -6807,7 +6793,7 @@
}
if (targetPkg != null) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Checking grant " + targetPkg + " permission to " + grantUri);
}
@@ -6815,7 +6801,7 @@
// If this is not a content: uri, we can't do anything with it.
if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Can't grant URI permission for non-content URI: " + grantUri);
return -1;
}
@@ -6833,7 +6819,7 @@
try {
targetUid = pm.getPackageUid(targetPkg, UserHandle.getUserId(callingUid));
if (targetUid < 0) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Can't grant URI permission no uid for: " + targetPkg);
return -1;
}
@@ -6846,7 +6832,7 @@
// First... does the target actually need this permission?
if (checkHoldingPermissionsLocked(pm, pi, grantUri, targetUid, modeFlags)) {
// No need to grant the target this permission.
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Target " + targetPkg + " already has full permission to " + grantUri);
return -1;
}
@@ -6943,7 +6929,7 @@
// to the uri, and the target doesn't. Let's now give this to
// the target.
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
final String authority = grantUri.uri.getAuthority();
@@ -7001,7 +6987,7 @@
*/
NeededUriGrants checkGrantUriPermissionFromIntentLocked(int callingUid,
String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Checking URI perm to data=" + (intent != null ? intent.getData() : null)
+ " clip=" + (intent != null ? intent.getClipData() : null)
+ " from " + intent + "; flags=0x"
@@ -7035,10 +7021,9 @@
return null;
}
if (targetUid < 0) {
- if (DEBUG_URI_PERMISSION) {
- Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg
- + " on user " + targetUserId);
- }
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+ "Can't grant URI permission no uid for: " + targetPkg
+ + " on user " + targetUserId);
return null;
}
}
@@ -7145,7 +7130,7 @@
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
perm.targetUid);
if (perms != null) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Removing " + perm.targetUid + " permission to " + perm.uri);
perms.remove(perm.uri);
@@ -7157,7 +7142,8 @@
}
private void revokeUriPermissionLocked(int callingUid, GrantUri grantUri, final int modeFlags) {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + grantUri);
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+ "Revoking all granted permissions to " + grantUri);
final IPackageManager pm = AppGlobals.getPackageManager();
final String authority = grantUri.uri.getAuthority();
@@ -7179,9 +7165,9 @@
final UriPermission perm = it.next();
if (perm.uri.sourceUserId == grantUri.sourceUserId
&& perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
- if (DEBUG_URI_PERMISSION)
- Slog.v(TAG, "Revoking non-owned " + perm.targetUid +
- " permission to " + perm.uri);
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+ "Revoking non-owned " + perm.targetUid
+ + " permission to " + perm.uri);
persistChanged |= perm.revokeModes(
modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
if (perm.modeFlags == 0) {
@@ -7211,8 +7197,7 @@
final UriPermission perm = it.next();
if (perm.uri.sourceUserId == grantUri.sourceUserId
&& perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
- if (DEBUG_URI_PERMISSION)
- Slog.v(TAG,
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
"Revoking " + perm.targetUid + " permission to " + perm.uri);
persistChanged |= perm.revokeModes(
modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
@@ -7397,7 +7382,7 @@
}
private void writeGrantedUriPermissions() {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG, "writeGrantedUriPermissions()");
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "writeGrantedUriPermissions()");
// Snapshot permissions so we can persist without lock
ArrayList<UriPermission.Snapshot> persist = Lists.newArrayList();
@@ -7445,7 +7430,7 @@
}
private void readGrantedUriPermissionsLocked() {
- if (DEBUG_URI_PERMISSION) Slog.v(TAG, "readGrantedUriPermissions()");
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "readGrantedUriPermissions()");
final long now = System.currentTimeMillis();
@@ -7623,9 +7608,8 @@
for (int i = 0; i < trimCount; i++) {
final UriPermission perm = persisted.get(i);
- if (DEBUG_URI_PERMISSION) {
- Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
- }
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+ "Trimming grant created at " + perm.persistedCreateTime);
perm.releasePersistableModes(~0);
removeUriPermissionIfNeededLocked(perm);
@@ -7855,7 +7839,7 @@
TaskRecord tr = mRecentTasks.get(i);
// Only add calling user or related users recent tasks
if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
- if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, not user: " + tr);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
continue;
}
@@ -7874,25 +7858,27 @@
// If the caller doesn't have the GET_TASKS permission, then only
// allow them to see a small subset of tasks -- their own and home.
if (!tr.isHomeTask() && tr.effectiveUid != callingUid) {
- if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, not allowed: " + tr);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
continue;
}
}
if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {
if (tr.stack != null && tr.stack.isHomeStack()) {
- if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, home stack task: " + tr);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+ "Skipping, home stack task: " + tr);
continue;
}
}
if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
// Don't include auto remove tasks that are finished or finishing.
- if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, auto-remove without activity: "
- + tr);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+ "Skipping, auto-remove without activity: " + tr);
continue;
}
if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0
&& !tr.isAvailable) {
- if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, unavail real act: " + tr);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+ "Skipping, unavail real act: " + tr);
continue;
}
@@ -8226,10 +8212,9 @@
*/
@Override
public void moveTaskToFront(int taskId, int flags, Bundle options) {
- enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
- "moveTaskToFront()");
+ enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
- if (DEBUG_STACK) Slog.d(TAG, "moveTaskToFront: moving taskId=" + taskId);
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
synchronized(this) {
moveTaskToFrontLocked(taskId, flags, options);
}
@@ -8389,8 +8374,8 @@
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
- if (DEBUG_STACK) Slog.d(TAG, "moveTaskToStack: moving task=" + taskId + " to stackId="
- + stackId + " toTop=" + toTop);
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
+ + " to stackId=" + stackId + " toTop=" + toTop);
mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -8801,7 +8786,7 @@
for (int i=0; i<r.conProviders.size(); i++) {
ContentProviderConnection conn = r.conProviders.get(i);
if (conn.provider == cpr) {
- if (DEBUG_PROVIDER) Slog.v(TAG,
+ if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
"Adding provider requested by "
+ r.processName + " from process "
+ cpr.info.processName + ": " + cpr.name.flattenToShortString()
@@ -8837,7 +8822,7 @@
ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (conn != null) {
cpr = conn.provider;
- if (DEBUG_PROVIDER) Slog.v(TAG,
+ if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
"Removing provider requested by "
+ conn.client.processName + " from process "
+ cpr.info.processName + ": " + cpr.name.flattenToShortString()
@@ -8965,7 +8950,7 @@
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
boolean success = updateOomAdjLocked(cpr.proc);
checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
- if (DEBUG_PROVIDER) Slog.i(TAG, "Adjust success: " + success);
+ if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
// NOTE: there is still a race here where a signal could be
// pending on the process even though we managed to update its
// adj level. Not sure what to do about this, but at least
@@ -8975,8 +8960,7 @@
// has been killed on us. We need to wait for a new
// process to be started, and make sure its death
// doesn't kill our process.
- Slog.i(TAG,
- "Existing provider " + cpr.name.flattenToShortString()
+ Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
checkTime(startTime, "getContentProviderImpl: before appDied");
@@ -9087,18 +9071,16 @@
return cpr.newHolder(null);
}
- if (DEBUG_PROVIDER) {
- RuntimeException e = new RuntimeException("here");
- Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null)
- + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
- }
+ if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
+ + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
+ + cpr.info.name + " callers=" + Debug.getCallers(6));
// This is single process, and our app is now connecting to it.
// See if we are already in the process of launching this
// provider.
final int N = mLaunchingProviders.size();
int i;
- for (i=0; i<N; i++) {
+ for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
@@ -9127,9 +9109,8 @@
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null) {
- if (DEBUG_PROVIDER) {
- Slog.d(TAG, "Installing in existing process " + proc);
- }
+ if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
+ "Installing in existing process " + proc);
if (!proc.pubProviders.containsKey(cpi.name)) {
checkTime(startTime, "getContentProviderImpl: scheduling install");
proc.pubProviders.put(cpi.name, cpr);
@@ -9844,7 +9825,7 @@
}
void logLockScreen(String msg) {
- if (DEBUG_LOCKSCREEN) Slog.d(TAG, Debug.getCallers(2) + ":" + msg
+ if (DEBUG_LOCKSCREEN) Slog.d(TAG_LOCKSCREEN, Debug.getCallers(2) + ":" + msg
+ " mLockScreenShown=" + lockScreenShownToString() + " mWakefulness="
+ PowerManagerInternal.wakefulnessToString(mWakefulness)
+ " mSleeping=" + mSleeping);
@@ -14916,8 +14897,8 @@
throw new IllegalArgumentException("File descriptors passed in Intent");
}
- if (DEBUG_SERVICE)
- Slog.v(TAG, "startService: " + service + " type=" + resolvedType);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
+ "startService: " + service + " type=" + resolvedType);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
@@ -14932,8 +14913,8 @@
ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, int userId)
throws TransactionTooLargeException {
synchronized(this) {
- if (DEBUG_SERVICE)
- Slog.v(TAG, "startServiceInPackage: " + service + " type=" + resolvedType);
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
+ "startServiceInPackage: " + service + " type=" + resolvedType);
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(null, service,
resolvedType, -1, uid, userId);
@@ -17399,11 +17380,11 @@
* Record new PSS sample for a process.
*/
void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) {
- EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss*1024, uss*1024);
+ EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024);
proc.lastPssTime = now;
proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
- if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
- + ": " + pss + " lastPss=" + proc.lastPss
+ if (DEBUG_PSS) Slog.d(TAG_PSS,
+ "PSS of " + proc.toShortString() + ": " + pss + " lastPss=" + proc.lastPss
+ " state=" + ProcessList.makeProcStateString(procState));
if (proc.initialIdlePss == 0) {
proc.initialIdlePss = pss;
@@ -17415,7 +17396,7 @@
Long check = mMemWatchProcesses.get(proc.processName);
if (check != null) {
- if ((pss*1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
+ if ((pss * 1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
if (!isDebuggable) {
if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
@@ -17449,7 +17430,7 @@
IApplicationThread thread = myProc.thread;
if (thread != null) {
try {
- if (DEBUG_PSS) Slog.d(TAG, "Requesting dump heap from "
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting dump heap from "
+ myProc + " to " + heapdumpFile);
thread.dumpHeap(true, heapdumpFile.toString(), fd);
} catch (RemoteException e) {
@@ -17485,7 +17466,7 @@
if (mPendingPssProcesses.size() == 0) {
mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
}
- if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of: " + proc);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting PSS of: " + proc);
proc.pssProcState = procState;
mPendingPssProcesses.add(proc);
}
@@ -17500,13 +17481,17 @@
return;
}
}
- if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of all procs! memLowered=" + memLowered);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting PSS of all procs! memLowered=" + memLowered);
mLastFullPssTime = now;
mFullPssPending = true;
mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
mPendingPssProcesses.clear();
- for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord app = mLruProcesses.get(i);
+ if (app.thread == null
+ || app.curProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
+ continue;
+ }
if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
app.pssProcState = app.setProcState;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
@@ -17712,7 +17697,7 @@
sb.append(" (");
sb.append((wtimeUsed*100)/realtimeSince);
sb.append("%)");
- Slog.i(TAG, sb.toString());
+ Slog.i(TAG_POWER, sb.toString());
sb.setLength(0);
sb.append("CPU for ");
app.toShortString(sb);
@@ -17723,7 +17708,7 @@
sb.append(" (");
sb.append((cputimeUsed*100)/uptimeSince);
sb.append("%)");
- Slog.i(TAG, sb.toString());
+ Slog.i(TAG_POWER, sb.toString());
}
// If a process has held a wake lock for more
// than 50% of the time during this period,
@@ -17822,8 +17807,8 @@
}
}
}
- if (app.setProcState < 0 || ProcessList.procStatesDifferForMem(app.curProcState,
- app.setProcState)) {
+ if (app.setProcState == ActivityManager.PROCESS_STATE_NONEXISTENT
+ || ProcessList.procStatesDifferForMem(app.curProcState, app.setProcState)) {
if (false && mTestPssMode && app.setProcState >= 0 && app.lastStateTime <= (now-200)) {
// Experimental code to more aggressively collect pss while
// running test... the problem is that this tends to collect
@@ -17840,7 +17825,7 @@
app.lastStateTime = now;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
mTestPssMode, isSleeping(), now);
- if (DEBUG_PSS) Slog.d(TAG, "Process state change from "
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
+ ProcessList.makeProcStateString(app.setProcState) + " to "
+ ProcessList.makeProcStateString(app.curProcState) + " next pss in "
+ (app.nextPssTime-now) + ": " + app);
@@ -17851,9 +17836,8 @@
requestPssLocked(app, app.setProcState);
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
mTestPssMode, isSleeping(), now);
- } else if (false && DEBUG_PSS) {
- Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
- }
+ } else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
+ "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
}
if (app.setProcState != app.curProcState) {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
@@ -17886,13 +17870,15 @@
}
if (changes != 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes);
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Changes in " + app + ": " + changes);
int i = mPendingProcessChanges.size()-1;
ProcessChangeItem item = null;
while (i >= 0) {
item = mPendingProcessChanges.get(i);
if (item.pid == app.pid) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item);
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Re-using existing item: " + item);
break;
}
i--;
@@ -17902,16 +17888,18 @@
final int NA = mAvailProcessChanges.size();
if (NA > 0) {
item = mAvailProcessChanges.remove(NA-1);
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item);
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Retreiving available item: " + item);
} else {
item = new ProcessChangeItem();
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item);
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Allocating new item: " + item);
}
item.changes = 0;
item.pid = app.pid;
item.uid = app.info.uid;
if (mPendingProcessChanges.size() == 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG,
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"*** Enqueueing dispatch processes changed!");
mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
}
@@ -17920,8 +17908,8 @@
item.changes |= changes;
item.processState = app.repProcState;
item.foregroundActivities = app.repForegroundActivities;
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item "
- + Integer.toHexString(System.identityHashCode(item))
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Item " + Integer.toHexString(System.identityHashCode(item))
+ " " + app.toShortString() + ": changes=" + item.changes
+ " procState=" + item.processState
+ " foreground=" + item.foregroundActivities
@@ -18677,7 +18665,7 @@
+ " does not match last path " + mMemWatchDumpFile);
return;
}
- if (DEBUG_PSS) Slog.d(TAG, "Dump heap finished for " + path);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Dump heap finished for " + path);
mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d34b33b..f3b18f5 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,8 +17,6 @@
package com.android.server.am;
import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerService.DEBUG_THUMBNAILS;
import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
@@ -75,6 +73,8 @@
*/
final class ActivityRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
+ private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+ private static final String TAG_THUMBNAILS = TAG + POSTFIX_THUMBNAILS;
private static final boolean SHOW_ACTIVITY_START_TIME = true;
static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
@@ -354,7 +354,7 @@
synchronized (mService) {
ActivityRecord r = tokenToActivityRecordLocked(this);
if (r != null) {
- if (DEBUG_SWITCH) Log.v(TAG, "windowsGone(): " + r);
+ if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r);
r.nowVisible = false;
return;
}
@@ -863,7 +863,7 @@
void updateThumbnailLocked(Bitmap newThumbnail, CharSequence description) {
if (newThumbnail != null) {
- if (DEBUG_THUMBNAILS) Slog.i(TAG,
+ if (DEBUG_THUMBNAILS) Slog.i(TAG_THUMBNAILS,
"Setting thumbnail of " + this + " to " + newThumbnail);
boolean thumbnailUpdated = task.setLastThumbnail(newThumbnail);
if (thumbnailUpdated && isPersistable()) {
@@ -1014,7 +1014,7 @@
void windowsVisibleLocked() {
mStackSupervisor.reportActivityVisibleLocked(this);
- if (DEBUG_SWITCH) Log.v(TAG, "windowsVisibleLocked(): " + this);
+ if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
if (!nowVisible) {
nowVisible = true;
lastVisibleTime = SystemClock.uptimeMillis();
@@ -1030,7 +1030,7 @@
if (size > 0) {
for (int i = 0; i < size; i++) {
ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
- if (DEBUG_SWITCH) Log.v(TAG, "Was waiting for visible: " + r);
+ if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
}
mStackSupervisor.mWaitingVisibleActivities.clear();
mStackSupervisor.scheduleIdleLocked();
@@ -1041,24 +1041,21 @@
}
ActivityRecord getWaitingHistoryRecordLocked() {
- // First find the real culprit... if we are waiting
- // for another app to start, then we have paused dispatching
- // for this activity.
- ActivityRecord r = this;
- if (mStackSupervisor.mWaitingVisibleActivities.contains(this)) {
+ // First find the real culprit... if this activity is waiting for
+ // another activity to start or has stopped, then the key dispatching
+ // timeout should not be caused by this.
+ if (mStackSupervisor.mWaitingVisibleActivities.contains(this) || stopped) {
final ActivityStack stack = mStackSupervisor.getFocusedStack();
- // Hmmm, who might we be waiting for?
- r = stack.mResumedActivity;
+ // Try to use the one which is closest to top.
+ ActivityRecord r = stack.mResumedActivity;
if (r == null) {
r = stack.mPausingActivity;
}
- // Both of those null? Fall back to 'this' again
- if (r == null) {
- r = this;
+ if (r != null) {
+ return r;
}
}
-
- return r;
+ return this;
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 0eb914b..a8deea3 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -17,14 +17,6 @@
package com.android.server.am;
import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerService.DEBUG_TRANSITION;
-import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
-import static com.android.server.am.ActivityManagerService.DEBUG_VISBILITY;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
@@ -96,6 +88,14 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+ private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
+ private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
+ private static final String TAG_STACK = TAG + POSTFIX_STACK;
+ private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+ private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+ private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
+ private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
+ private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
private static final boolean VALIDATE_TOKENS = false;
@@ -538,23 +538,23 @@
// If documentData is non-null then it must match the existing task data.
Uri documentData = isDocument ? intent.getData() : null;
- if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + target + " in " + this);
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
if (task.voiceSession != null) {
// We never match voice sessions; those always run independently.
- if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": voice session");
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
continue;
}
if (task.userId != userId) {
// Looking for a different task.
- if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": different user");
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
continue;
}
final ActivityRecord r = task.getTopActivity();
if (r == null || r.finishing || r.userId != userId ||
r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
- if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": mismatch root " + r);
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
continue;
}
@@ -573,34 +573,32 @@
taskDocumentData = null;
}
- if (DEBUG_TASKS) Slog.d(TAG, "Comparing existing cls="
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
+ taskIntent.getComponent().flattenToShortString()
+ "/aff=" + r.task.rootAffinity + " to new cls="
+ intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
if (!isDocument && !taskIsDocument && task.rootAffinity != null) {
if (task.rootAffinity.equals(target.taskAffinity)) {
- if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!");
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity!");
return r;
}
} else if (taskIntent != null && taskIntent.getComponent() != null &&
taskIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
- if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
//dump();
- if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
- + r.intent);
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+ "For Intent " + intent + " bringing to top: " + r.intent);
return r;
} else if (affinityIntent != null && affinityIntent.getComponent() != null &&
affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
- if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
//dump();
- if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
- + r.intent);
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+ "For Intent " + intent + " bringing to top: " + r.intent);
return r;
- } else if (DEBUG_TASKS) {
- Slog.d(TAG, "Not a match: " + task);
- }
+ } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
return null;
@@ -652,7 +650,7 @@
for (int i = 0; i < index; ) {
TaskRecord task = mTaskHistory.get(i);
if (isCurrentProfileLocked(task.userId)) {
- if (DEBUG_TASKS) Slog.d(TAG, "switchUserLocked: stack=" + getStackId() +
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "switchUserLocked: stack=" + getStackId() +
" moving " + task + " to top");
mTaskHistory.remove(i);
mTaskHistory.add(task);
@@ -739,14 +737,15 @@
boolean checkReadyForSleepLocked() {
if (mResumedActivity != null) {
// Still have something resumed; can't sleep until it is paused.
- if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause " + mResumedActivity);
- if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
+ if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+ "Sleep => pause with userLeaving=false");
startPausingLocked(false, true, false, false);
return true;
}
if (mPausingActivity != null) {
// Still waiting for something to pause; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
return true;
}
@@ -829,7 +828,7 @@
}
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
- else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
+ else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
@@ -847,7 +846,7 @@
mService.updateCpuStats();
if (prev.app != null && prev.app.thread != null) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
@@ -881,8 +880,8 @@
// key dispatch; the same activity will pick it up again on wakeup.
if (!uiSleeping) {
prev.pauseKeyDispatchingLocked();
- } else {
- if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
+ } else if (DEBUG_PAUSE) {
+ Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off");
}
if (dontWait) {
@@ -899,14 +898,14 @@
msg.obj = prev;
prev.pauseTime = SystemClock.uptimeMillis();
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
- if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
return true;
}
} else {
// This activity failed to schedule the
// pause, so just treat it as being paused now.
- if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
if (!resuming) {
mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
}
@@ -915,8 +914,8 @@
}
final void activityPausedLocked(IBinder token, boolean timeout) {
- if (DEBUG_PAUSE) Slog.v(
- TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
+ "Activity paused: token=" + token + ", timeout=" + timeout);
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
@@ -977,18 +976,18 @@
private void completePauseLocked(boolean resumeNext) {
ActivityRecord prev = mPausingActivity;
- if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
if (prev != null) {
prev.state = ActivityState.PAUSED;
if (prev.finishing) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
} else if (prev.app != null) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending stop: " + prev);
if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
- if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
- TAG, "Complete pause, no longer waiting: " + prev);
+ if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
+ "Complete pause, no longer waiting: " + prev);
}
if (prev.configDestroy) {
// The previous is being paused because the configuration
@@ -996,7 +995,7 @@
// To juggle the fact that we are also starting a new
// instance right now, we need to first completely stop
// the current instance before starting the new one.
- if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Destroying after pause: " + prev);
destroyActivityLocked(prev, true, "pause-config");
} else if (!hasVisibleBehindActivity()) {
// If we were visible then resumeTopActivities will release resources before
@@ -1008,14 +1007,14 @@
// 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, "To many pending stops, forcing idle");
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "To many pending stops, forcing idle");
mStackSupervisor.scheduleIdleLocked();
} else {
mStackSupervisor.checkReadyForSleepLocked();
}
}
} else {
- if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
prev = null;
}
// It is possible the activity was freezing the screen before it was paused.
@@ -1246,10 +1245,15 @@
if (top == null) {
return;
}
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "ensureActivitiesVisible behind " + top
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "ensureActivitiesVisible behind " + top
+ " configChanges=0x" + Integer.toHexString(configChanges));
+ if (DEBUG_STATES && starting != null && starting.task.stack == this) {
+ Slog.d(TAG, "ensureActivitiesVisibleLocked: starting=" + starting + " state="
+ + starting.state + " fullscreen=" + starting.fullscreen + " top=" + top
+ + " state=" + top.state + " fullscreen=" + top.fullscreen);
+ }
if (mTranslucentActivityWaiting != top) {
mUndrawnActivitiesBelowTopTranslucent.clear();
if (mTranslucentActivityWaiting != null) {
@@ -1280,8 +1284,8 @@
// mLaunchingBehind: Activities launching behind are at the back of the task stack
// but must be drawn initially for the animation as though they were visible.
if (!behindFullscreen || r.mLaunchTaskBehind) {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Make visible? " + r + " finishing=" + r.finishing
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Make visible? " + r + " finishing=" + r.finishing
+ " state=" + r.state);
// First: if this is not the current activity being started, make
@@ -1294,13 +1298,14 @@
// This activity needs to be visible, but isn't even
// running... get it started, but don't resume it
// at this point.
- if (DEBUG_VISBILITY) Slog.v(TAG, "Start and freeze screen for " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Start and freeze screen for " + r);
if (r != starting) {
r.startFreezingScreenLocked(r.app, configChanges);
}
if (!r.visible || r.mLaunchTaskBehind) {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Starting and making visible: " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Starting and making visible: " + r);
setVisible(r, true);
}
if (r != starting) {
@@ -1310,7 +1315,8 @@
} else if (r.visible) {
// If this activity is already visible, then there is nothing
// else to do here.
- if (DEBUG_VISBILITY) Slog.v(TAG, "Skipping: already visible at " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Skipping: already visible at " + r);
r.stopFreezingScreenLocked(false);
try {
if (r.returningOptions != null) {
@@ -1326,8 +1332,8 @@
if (r.state != ActivityState.RESUMED && r != starting) {
// If this activity is paused, tell it
// to now show its window.
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Making visible and scheduling visibility: " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Making visible and scheduling visibility: " + r);
try {
if (mTranslucentActivityWaiting != null) {
r.updateOptionsLocked(r.returningOptions);
@@ -1352,29 +1358,28 @@
if (r.fullscreen) {
// At this point, nothing else needs to be shown
- if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r);
behindFullscreen = true;
} else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
- if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r);
behindFullscreen = true;
}
} else {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Make invisible? " + r + " finishing=" + r.finishing
- + " state=" + r.state
- + " behindFullscreen=" + behindFullscreen);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Make invisible? " + r + " finishing=" + r.finishing
+ + " state=" + r.state + " behindFullscreen=" + behindFullscreen);
// Now for any activities that aren't visible to the user, make
// sure they no longer are keeping the screen frozen.
if (r.visible) {
- if (DEBUG_VISBILITY) Slog.v(TAG, "Making invisible: " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r);
try {
setVisible(r, false);
switch (r.state) {
case STOPPING:
case STOPPED:
if (r.app != null && r.app.thread != null) {
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Scheduling invisibility: " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Scheduling invisibility: " + r);
r.app.thread.scheduleWindowVisibility(r.appToken, false);
}
break;
@@ -1405,7 +1410,7 @@
+ r.intent.getComponent(), e);
}
} else {
- if (DEBUG_VISBILITY) Slog.v(TAG, "Already invisible: " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
}
}
}
@@ -1475,7 +1480,8 @@
}
if (r.state == ActivityState.INITIALIZING && r.mStartingWindowShown) {
- if (DEBUG_VISBILITY) Slog.w(TAG, "Found orphaned starting window " + r);
+ if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY,
+ "Found orphaned starting window " + r);
r.mStartingWindowShown = false;
mWindowManager.removeAppStartingWindow(r.appToken);
}
@@ -1518,7 +1524,7 @@
}
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
- if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+ if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
if (!mService.mBooting && !mService.mBooted) {
// Not ready yet!
@@ -1636,12 +1642,12 @@
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);
- if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
// If we are currently pausing an activity, then don't do anything
// until that is done.
if (!mStackSupervisor.allPausedActivitiesComplete()) {
- if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG,
+ if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
@@ -1716,8 +1722,8 @@
if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
&& next != null && !next.nowVisible) {
mStackSupervisor.mWaitingVisibleActivities.add(prev);
- if (DEBUG_SWITCH) Slog.v(
- TAG, "Resuming top, waiting visible to hide: " + prev);
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+ "Resuming top, waiting visible to hide: " + prev);
} else {
// The next activity is already visible, so hide the previous
// activity's windows right now so we can show the new one ASAP.
@@ -1729,16 +1735,16 @@
// new one is found to be full-screen or not.
if (prev.finishing) {
mWindowManager.setAppVisibility(prev.appToken, false);
- if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
- + prev + ", waitingVisible="
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+ "Not waiting for visible to hide: " + prev + ", waitingVisible="
+ mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+ ", nowVisible=" + next.nowVisible);
} else {
- if (DEBUG_SWITCH) Slog.v(TAG,
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Previous already visible but still waiting to hide: " + prev
- + ", waitingVisible="
- + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
- + ", nowVisible=" + next.nowVisible);
+ + ", waitingVisible="
+ + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+ + ", nowVisible=" + next.nowVisible);
}
}
}
@@ -1760,7 +1766,7 @@
boolean anim = true;
if (prev != null) {
if (prev.finishing) {
- if (DEBUG_TRANSITION) Slog.v(TAG,
+ if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare close transition: prev=" + prev);
if (mNoAnimActivities.contains(prev)) {
anim = false;
@@ -1773,7 +1779,8 @@
mWindowManager.setAppWillBeHidden(prev.appToken);
mWindowManager.setAppVisibility(prev.appToken, false);
} else {
- if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: prev=" + prev);
+ if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
+ "Prepare open transition: prev=" + prev);
if (mNoAnimActivities.contains(next)) {
anim = false;
mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
@@ -1790,7 +1797,7 @@
mWindowManager.setAppVisibility(prev.appToken, false);
}
} else {
- if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: no previous");
+ if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
if (mNoAnimActivities.contains(next)) {
anim = false;
mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
@@ -1812,7 +1819,7 @@
ActivityStack lastStack = mStackSupervisor.getLastStack();
if (next.app != null && next.app.thread != null) {
- if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next);
// This activity is now becoming visible.
mWindowManager.setAppVisibility(next.appToken, true);
@@ -1877,9 +1884,8 @@
if (a != null) {
final int N = a.size();
if (!next.finishing && N > 0) {
- if (DEBUG_RESULTS) Slog.v(
- TAG, "Delivering results to " + next
- + ": " + a);
+ if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+ "Delivering results to " + next + ": " + a);
next.app.thread.scheduleSendResult(next.appToken, a);
}
}
@@ -1956,7 +1962,7 @@
next.labelRes, next.icon, next.logo, next.windowFlags,
null, true);
}
- if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
}
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Restarting " + next);
mStackSupervisor.startSpecificActivityLocked(next, true, true);
@@ -2078,7 +2084,7 @@
// activity
if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
mStackSupervisor.mUserLeaving = false;
- if (DEBUG_USER_LEAVING) Slog.v(TAG,
+ if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"startActivity() behind front, mUserLeaving=false");
}
@@ -2103,9 +2109,9 @@
if (proc == null || proc.thread == null) {
showStartingIcon = true;
}
- if (DEBUG_TRANSITION) Slog.v(TAG,
+ if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
- if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+ if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, keepCurTransition);
mNoAnimActivities.add(r);
} else {
@@ -2275,13 +2281,13 @@
// same task affinity as the one we are moving,
// then merge it into the same task.
targetTask = bottom.task;
- if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
+ " out to bottom task " + bottom.task);
} else {
targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
null, null, null, false);
targetTask.affinityIntent = target.intent;
- if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
+ " out to new task " + target.task);
}
@@ -2306,8 +2312,8 @@
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing activity " + p + " from task="
+ task + " adding to task=" + targetTask
+ " Callers=" + Debug.getCallers(4));
- if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
- + " out to target's task " + target.task);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Pushing next activity " + p + " out to target's task " + target.task);
p.setTask(targetTask, null);
targetTask.addActivityAtBottom(p);
@@ -2349,7 +2355,7 @@
noOptions = false;
}
}
- if (DEBUG_TASKS) Slog.w(TAG,
+ if (DEBUG_TASKS) Slog.w(TAG_TASKS,
"resetTaskIntendedTask: calling finishActivity on " + p);
if (finishActivityLocked(
p, Activity.RESULT_CANCELED, null, "reset-task", false)) {
@@ -2423,7 +2429,8 @@
// in a task that is not currently on top.)
if (forceReset || finishOnTaskLaunch) {
final int start = replyChainEnd >= 0 ? replyChainEnd : i;
- if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index " + start + " to " + i);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Finishing task at index " + start + " to " + i);
for (int srcPos = start; srcPos >= i; --srcPos) {
final ActivityRecord p = activities.get(srcPos);
if (p.finishing) {
@@ -2439,8 +2446,9 @@
}
final int start = replyChainEnd >= 0 ? replyChainEnd : i;
- if (DEBUG_TASKS) Slog.v(TAG, "Reparenting from task=" + affinityTask + ":"
- + start + "-" + i + " to task=" + task + ":" + taskInsertionPoint);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Reparenting from task=" + affinityTask + ":" + start + "-" + i
+ + " to task=" + task + ":" + taskInsertionPoint);
for (int srcPos = start; srcPos >= i; --srcPos) {
final ActivityRecord p = activities.get(srcPos);
p.setTask(task, null);
@@ -2449,8 +2457,8 @@
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + p
+ " to stack at " + task,
new RuntimeException("here").fillInStackTrace());
- if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p + " from " + srcPos
- + " in to resetting task " + task);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
+ + " from " + srcPos + " in to resetting task " + task);
mWindowManager.setAppTask(p.appToken, taskId);
}
mWindowManager.moveTaskToTop(taskId);
@@ -2608,7 +2616,7 @@
}
final void stopActivityLocked(ActivityRecord r) {
- if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
+ if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + r);
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
@@ -2633,8 +2641,8 @@
if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
+ " (stop requested)");
r.state = ActivityState.STOPPING;
- if (DEBUG_VISBILITY) Slog.v(
- TAG, "Stopping visible=" + r.visible + " for " + r);
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Stopping visible=" + r.visible + " for " + r);
if (!r.visible) {
mWindowManager.setAppVisibility(r.appToken, false);
}
@@ -2771,7 +2779,7 @@
// send the result
ActivityRecord resultTo = r.resultTo;
if (resultTo != null) {
- if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
+ if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Adding result to " + resultTo
+ " who=" + r.resultWho + " req=" + r.requestCode
+ " res=" + resultCode + " data=" + resultData);
if (resultTo.userId != r.userId) {
@@ -2788,7 +2796,7 @@
resultData);
r.resultTo = null;
}
- else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
+ else if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "No result destination from " + r);
// Make sure this HistoryRecord is not holding on to other resources,
// because clients have remote IPC references to this object so we
@@ -2836,7 +2844,7 @@
if (mResumedActivity == r) {
boolean endTask = index <= 0;
- if (DEBUG_VISBILITY || DEBUG_TRANSITION) Slog.v(TAG,
+ if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare close transition: finishing " + r);
mWindowManager.prepareAppTransition(endTask
? AppTransition.TRANSIT_TASK_CLOSE
@@ -2846,8 +2854,9 @@
mWindowManager.setAppVisibility(r.appToken, false);
if (mPausingActivity == null) {
- if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
- if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
+ if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+ "finish() => pause with userLeaving=false");
startPausingLocked(false, false, false, false);
}
@@ -2857,10 +2866,10 @@
} else if (r.state != ActivityState.PAUSING) {
// If the activity is PAUSING, we will complete the finish once
// it is done pausing; else we can just directly finish it here.
- if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
return finishCurrentActivityLocked(r, FINISH_AFTER_PAUSE, oomAdj) == null;
} else {
- if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
}
return false;
@@ -3155,7 +3164,7 @@
}
final TaskRecord task = r.task;
if (task != null && task.removeActivity(r)) {
- if (DEBUG_STACK) Slog.i(TAG,
+ if (DEBUG_STACK) Slog.i(TAG_STACK,
"removeActivityFromHistoryLocked: last activity removed from " + this);
if (mStackSupervisor.isFrontStack(this) && task == topTask() &&
task.isOverHomeStack()) {
@@ -3208,7 +3217,7 @@
continue;
}
if (r.isDestroyable()) {
- if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.state
+ " resumed=" + mResumedActivity
+ " pausing=" + mPausingActivity + " for reason " + reason);
if (destroyActivityLocked(r, true, reason)) {
@@ -3224,8 +3233,8 @@
final boolean safelyDestroyActivityLocked(ActivityRecord r, String reason) {
if (r.isDestroyable()) {
- if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
- + " resumed=" + mResumedActivity
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+ "Destroying " + r + " in state " + r.state + " resumed=" + mResumedActivity
+ " pausing=" + mPausingActivity + " for reason " + reason);
return destroyActivityLocked(r, true, reason);
}
@@ -3283,9 +3292,9 @@
* but then create a new client-side object for this same HistoryRecord.
*/
final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
- if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(
- TAG, "Removing activity from " + reason + ": token=" + r
- + ", app=" + (r.app != null ? r.app.processName : "(null)"));
+ if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(TAG_SWITCH,
+ "Removing activity from " + reason + ": token=" + r
+ + ", app=" + (r.app != null ? r.app.processName : "(null)"));
EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
r.userId, System.identityHashCode(r),
r.task.taskId, r.shortComponentName, reason);
@@ -3317,7 +3326,7 @@
boolean skipDestroy = false;
try {
- if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
+ if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
r.configChangeFlags);
} catch (Exception e) {
@@ -3579,8 +3588,8 @@
for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
if (task.taskType == homeStackTaskType) {
- if (DEBUG_TASKS || DEBUG_STACK)
- Slog.d(TAG, "moveHomeStackTaskToTop: moving " + task);
+ if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG_STACK,
+ "moveHomeStackTaskToTop: moving " + task);
mTaskHistory.remove(taskNdx);
mTaskHistory.add(top, task);
updateTaskMovement(task, true);
@@ -3591,7 +3600,7 @@
final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, Bundle options,
String reason) {
- if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
final int numTasks = mTaskHistory.size();
final int index = mTaskHistory.indexOf(tr);
@@ -3613,7 +3622,7 @@
ActivityRecord r = topRunningActivityLocked(null);
mService.setFocusedActivityLocked(r, reason);
- if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr);
+ if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
if (r != null) {
@@ -3677,7 +3686,7 @@
}
}
- if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to back transition: task=" + taskId);
+ if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + taskId);
boolean prevIsHome = false;
if (tr.isOverHomeStack()) {
@@ -3907,8 +3916,8 @@
results = r.results;
newIntents = r.newIntents;
}
- if (DEBUG_SWITCH) Slog.v(TAG, "Relaunching: " + r
- + " with results=" + results + " newIntents=" + newIntents
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+ "Relaunching: " + r + " with results=" + results + " newIntents=" + newIntents
+ " andResume=" + andResume);
EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
: EventLogTags.AM_RELAUNCH_ACTIVITY, r.userId, System.identityHashCode(r),
@@ -3919,8 +3928,8 @@
mStackSupervisor.removeChildActivityContainers(r);
try {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Moving to " +
- (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r);
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
+ "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r);
r.forceNewConfig = false;
r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
!andResume, new Configuration(mService.mConfiguration),
@@ -3929,7 +3938,7 @@
// the caller will only pass in 'andResume' if this activity is
// currently resumed, which implies we aren't sleeping.
} catch (RemoteException e) {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Relaunch failed", e);
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
}
if (andResume) {
@@ -4082,8 +4091,7 @@
public void unhandledBackLocked() {
final int top = mTaskHistory.size() - 1;
- if (DEBUG_SWITCH) Slog.d(
- TAG, "Performing unhandledBack(): top activity at " + top);
+ if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Performing unhandledBack(): top activity at " + top);
if (top >= 0) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(top).mActivities;
int activityTop = activities.size() - 1;
@@ -4101,7 +4109,7 @@
*/
boolean handleAppDiedLocked(ProcessRecord app) {
if (mPausingActivity != null && mPausingActivity.app == app) {
- if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG,
+ if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
"App died while pausing: " + mPausingActivity);
mPausingActivity = null;
}
@@ -4241,7 +4249,7 @@
}
if (mTaskHistory.isEmpty()) {
- if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack=" + this);
+ if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
final boolean notHomeStack = !isHomeStack();
if (isOnHomeDisplay()) {
String myReason = reason + " leftTaskHistoryEmpty";
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f874244..669dff8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -23,17 +23,11 @@
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityStack.ActivityState.*;
import android.app.Activity;
import android.app.ActivityManager;
@@ -120,6 +114,13 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
+ private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
+ private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
+ private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+ private static final String TAG_STACK = TAG + POSTFIX_STACK;
+ private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+ private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+ private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
static final boolean DEBUG = DEBUG_ALL || false;
static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
@@ -381,7 +382,7 @@
}
void notifyActivityDrawnForKeyguard() {
- if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+ if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
mWindowManager.notifyActivityDrawnForKeyguard();
}
@@ -422,7 +423,7 @@
// The home stack should either be at the top or bottom of the stack list.
if ((toFront && (stacks.get(topNdx) != mHomeStack))
|| (!toFront && (stacks.get(0) != mHomeStack))) {
- if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old="
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "moveHomeTask: topStack old="
+ ((lastFocusedStack != null) ? lastFocusedStack : stacks.get(topNdx))
+ " new=" + mFocusedStack);
stacks.remove(mHomeStack);
@@ -510,10 +511,10 @@
}
// Don't give up! Look in recents.
- if (DEBUG_RECENTS) Slog.v(TAG, "Looking for task id=" + id + " in recents");
+ if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents");
TaskRecord task = mRecentTasks.taskForIdLocked(id);
if (task == null) {
- if (DEBUG_RECENTS) Slog.d(TAG, "\tDidn't find task id=" + id + " in recents");
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "\tDidn't find task id=" + id + " in recents");
return null;
}
@@ -522,10 +523,11 @@
}
if (!restoreRecentTaskLocked(task)) {
- if (DEBUG_RECENTS) Slog.w(TAG, "Couldn't restore task id=" + id + " found in recents");
+ if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
+ "Couldn't restore task id=" + id + " found in recents");
return null;
}
- if (DEBUG_RECENTS) Slog.w(TAG, "Restored task id=" + id + " from in recents");
+ if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, "Restored task id=" + id + " from in recents");
return task;
}
@@ -633,14 +635,14 @@
final ActivityStack stack = stacks.get(stackNdx);
if (isFrontStack(stack)) {
final ActivityRecord r = stack.mResumedActivity;
- if (r != null && r.state != ActivityState.RESUMED) {
+ if (r != null && r.state != RESUMED) {
return false;
}
}
}
}
// TODO: Not sure if this should check if all Paused are complete too.
- if (DEBUG_STACK) Slog.d(TAG,
+ if (DEBUG_STACK) Slog.d(TAG_STACK,
"allResumedActivitiesComplete: mLastFocusedStack changing from=" +
mLastFocusedStack + " to=" + mFocusedStack);
mLastFocusedStack = mFocusedStack;
@@ -648,17 +650,21 @@
}
boolean allResumedActivitiesVisible() {
+ boolean foundResumed = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
final ActivityRecord r = stack.mResumedActivity;
- if (r != null && (!r.nowVisible || mWaitingVisibleActivities.contains(r))) {
- return false;
+ if (r != null) {
+ if (!r.nowVisible || mWaitingVisibleActivities.contains(r)) {
+ return false;
+ }
+ foundResumed = true;
}
}
}
- return true;
+ return foundResumed;
}
/**
@@ -690,9 +696,7 @@
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
final ActivityRecord r = stack.mPausingActivity;
- if (r != null && r.state != ActivityState.PAUSED
- && r.state != ActivityState.STOPPED
- && r.state != ActivityState.STOPPING) {
+ if (r != null && r.state != PAUSED && r.state != STOPPED && r.state != STOPPING) {
if (DEBUG_STATES) {
Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
pausing = false;
@@ -897,7 +901,7 @@
ActivityContainer container = (ActivityContainer)iContainer;
synchronized (mService) {
if (container != null && container.mParentActivity != null &&
- container.mParentActivity.state != ActivityState.RESUMED) {
+ container.mParentActivity.state != RESUMED) {
// Cannot start a child activity if the parent is not resumed.
return ActivityManager.START_CANCELED;
}
@@ -1027,7 +1031,7 @@
} while (!outResult.timeout && outResult.who == null);
} else if (res == ActivityManager.START_TASK_TO_FRONT) {
ActivityRecord r = stack.topRunningActivityLocked(null);
- if (r.nowVisible && r.state == ActivityState.RESUMED) {
+ if (r.nowVisible && r.state == RESUMED) {
outResult.timeout = false;
outResult.who = new ComponentName(r.info.packageName, r.info.name);
outResult.totalTime = 0;
@@ -1178,10 +1182,9 @@
results = r.results;
newIntents = r.newIntents;
}
- if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
- + " icicle=" + r.icicle
- + " with results=" + results + " newIntents=" + newIntents
- + " andResume=" + andResume);
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+ "Launching: " + r + " icicle=" + r.icicle + " with results=" + results
+ + " newIntents=" + newIntents + " andResume=" + andResume);
if (andResume) {
EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
r.userId, System.identityHashCode(r),
@@ -1290,7 +1293,7 @@
// other state.
if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
+ " (starting in stopped state)");
- r.state = ActivityState.STOPPED;
+ r.state = STOPPED;
r.stopped = true;
}
@@ -1381,8 +1384,8 @@
ActivityRecord resultRecord = null;
if (resultTo != null) {
sourceRecord = isInAnyStackLocked(resultTo);
- if (DEBUG_RESULTS) Slog.v(
- TAG, "Will send result to " + resultTo + " " + sourceRecord);
+ if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+ "Will send result to " + resultTo + " " + sourceRecord);
if (sourceRecord != null) {
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
@@ -1726,7 +1729,8 @@
// We'll invoke onUserLeaving before onPause only if the launching
// activity did not explicitly state that this is an automated launch.
mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
- if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving);
+ if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+ "startActivity() => mUserLeaving=" + mUserLeaving);
// If the caller has asked not to resume at this point, we make note
// of this in the record so that we can skip it when trying to find
@@ -1933,7 +1937,7 @@
}
}
if (!movedToFront) {
- if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
+ " from " + intentActivity);
targetStack.moveToFront("intentActivityFound");
}
@@ -2139,8 +2143,8 @@
newTaskIntent != null ? newTaskIntent : intent,
voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
taskToAffiliate);
- if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
- r.task);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Starting new activity " + r + " in new task " + r.task);
} else {
r.setTask(reuseTask, taskToAffiliate);
}
@@ -2207,7 +2211,7 @@
// to keep the new one in the same task as the one that is starting
// it.
r.setTask(sourceTask, null);
- if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
+ " in existing task " + r.task + " from source " + sourceRecord);
} else if (inTask != null) {
@@ -2246,7 +2250,7 @@
}
r.setTask(inTask, null);
- if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
+ " in explicit task " + r.task);
} else {
@@ -2259,7 +2263,7 @@
r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
r.info, intent, null, null, true), null);
mWindowManager.moveTaskToTop(r.task.taskId);
- if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
+ " in new guessed " + r.task);
}
@@ -2599,8 +2603,8 @@
return;
}
task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options, reason);
- if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack="
- + task.stack);
+ if (DEBUG_STACK) Slog.d(TAG_STACK,
+ "findTaskToMoveToFront: moved to front of stack=" + task.stack);
}
ActivityStack getStack(int stackId) {
@@ -2793,20 +2797,20 @@
stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
// Restore home stack to top.
moveHomeStack(true, "restoreRecentTask");
- if (DEBUG_RECENTS)
- Slog.v(TAG, "Created stack=" + stack + " for recents restoration.");
+ if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
+ "Created stack=" + stack + " for recents restoration.");
}
if (stack == null) {
// What does this mean??? Not sure how we would get here...
- if (DEBUG_RECENTS)
- Slog.v(TAG, "Unable to find/create stack to restore recent task=" + task);
+ if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
+ "Unable to find/create stack to restore recent task=" + task);
return false;
}
stack.addTask(task, false, false);
- if (DEBUG_RECENTS)
- Slog.v(TAG, "Added restored task=" + task + " to stack=" + stack);
+ if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
+ "Added restored task=" + task + " to stack=" + stack);
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
@@ -2839,18 +2843,18 @@
}
ActivityRecord findTaskLocked(ActivityRecord r) {
- if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r);
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!r.isApplicationActivity() && !stack.isHomeStack()) {
- if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (home activity) " + stack);
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (home activity) " + stack);
continue;
}
if (!stack.mActivityContainer.isEligibleForNewTasks()) {
- if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " +
- stack);
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+ "Skipping stack: (new task not allowed) " + stack);
continue;
}
final ActivityRecord ar = stack.findTaskLocked(r);
@@ -2859,7 +2863,7 @@
}
}
}
- if (DEBUG_TASKS) Slog.d(TAG, "No task found");
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "No task found");
return null;
}
@@ -2968,7 +2972,7 @@
if (mStoppingActivities.size() > 0) {
// Still need to tell some activities to stop; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop "
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
+ mStoppingActivities.size() + " activities");
scheduleIdleLocked();
dontSleep = true;
@@ -2976,7 +2980,7 @@
if (mGoingToSleepActivities.size() > 0) {
// Still need to tell some activities to sleep; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to sleep "
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
+ mGoingToSleepActivities.size() + " activities");
dontSleep = true;
}
@@ -3127,16 +3131,14 @@
// First, if we find an activity that is in the process of being destroyed,
// then we just aren't going to do anything for now; we want things to settle
// down before we try to prune more activities.
- if (r.finishing || r.state == ActivityState.DESTROYING
- || r.state == ActivityState.DESTROYED) {
+ if (r.finishing || r.state == DESTROYING || r.state == DESTROYED) {
if (DEBUG_RELEASE) Slog.d(TAG, "Abort release; already destroying: " + r);
return;
}
// Don't consider any activies that are currently not in a state where they
// can be destroyed.
- if (r.visible || !r.stopped || !r.haveState
- || r.state == ActivityState.RESUMED || r.state == ActivityState.PAUSING
- || r.state == ActivityState.PAUSED || r.state == ActivityState.STOPPING) {
+ if (r.visible || !r.stopped || !r.haveState || r.state == RESUMED || r.state == PAUSING
+ || r.state == PAUSED || r.state == STOPPING) {
if (DEBUG_RELEASE) Slog.d(TAG, "Not releasing in-use activity: " + r);
continue;
}
@@ -3254,39 +3256,34 @@
}
void validateTopActivitiesLocked() {
- // FIXME
-/* for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = stacks.get(stackNdx);
- final ActivityRecord r = stack.topRunningActivityLocked(null);
- final ActivityState state = r == null ? ActivityState.DESTROYED : r.state;
- if (isFrontStack(stack)) {
- if (r == null) {
- Slog.e(TAG, "validateTop...: null top activity, stack=" + stack);
+ for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = stacks.get(stackNdx);
+ final ActivityRecord r = stack.topRunningActivityLocked(null);
+ final ActivityState state = r == null ? DESTROYED : r.state;
+ if (isFrontStack(stack)) {
+ if (r == null) Slog.e(TAG,
+ "validateTop...: null top activity, stack=" + stack);
+ else {
+ final ActivityRecord pausing = stack.mPausingActivity;
+ if (pausing != null && pausing == r) Slog.e(TAG,
+ "validateTop...: top stack has pausing activity r=" + r
+ + " state=" + state);
+ if (state != INITIALIZING && state != RESUMED) Slog.e(TAG,
+ "validateTop...: activity in front not resumed r=" + r
+ + " state=" + state);
+ }
} else {
- final ActivityRecord pausing = stack.mPausingActivity;
- if (pausing != null && pausing == r) {
- Slog.e(TAG, "validateTop...: top stack has pausing activity r=" + r +
- " state=" + state);
- }
- if (state != ActivityState.INITIALIZING && state != ActivityState.RESUMED) {
- Slog.e(TAG, "validateTop...: activity in front not resumed r=" + r +
- " state=" + state);
- }
- }
- } else {
- final ActivityRecord resumed = stack.mResumedActivity;
- if (resumed != null && resumed == r) {
- Slog.e(TAG, "validateTop...: back stack has resumed activity r=" + r +
- " state=" + state);
- }
- if (r != null && (state == ActivityState.INITIALIZING
- || state == ActivityState.RESUMED)) {
- Slog.e(TAG, "validateTop...: activity in back resumed r=" + r +
- " state=" + state);
+ final ActivityRecord resumed = stack.mResumedActivity;
+ if (resumed != null && resumed == r) Slog.e(TAG,
+ "validateTop...: back stack has resumed activity r=" + r
+ + " state=" + state);
+ if (r != null && (state == INITIALIZING || state == RESUMED)) Slog.e(TAG,
+ "validateTop...: activity in back resumed r=" + r + " state=" + state);
}
}
}
-*/
}
public void dump(PrintWriter pw, String prefix) {
@@ -3512,7 +3509,7 @@
mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0));
}
- public void handleDisplayAddedLocked(int displayId) {
+ private void handleDisplayAdded(int displayId) {
boolean newDisplay;
synchronized (mService) {
newDisplay = mActivityDisplays.get(displayId) == null;
@@ -3530,7 +3527,7 @@
}
}
- public void handleDisplayRemovedLocked(int displayId) {
+ private void handleDisplayRemoved(int displayId) {
synchronized (mService) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay != null) {
@@ -3544,7 +3541,7 @@
mWindowManager.onDisplayRemoved(displayId);
}
- public void handleDisplayChangedLocked(int displayId) {
+ private void handleDisplayChanged(int displayId) {
synchronized (mService) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay != null) {
@@ -3554,7 +3551,7 @@
mWindowManager.onDisplayChanged(displayId);
}
- StackInfo getStackInfo(ActivityStack stack) {
+ private StackInfo getStackInfoLocked(ActivityStack stack) {
StackInfo info = new StackInfo();
mWindowManager.getStackBounds(stack.mStackId, info.bounds);
info.displayId = Display.DEFAULT_DISPLAY;
@@ -3580,7 +3577,7 @@
StackInfo getStackInfoLocked(int stackId) {
ActivityStack stack = getStack(stackId);
if (stack != null) {
- return getStackInfo(stack);
+ return getStackInfoLocked(stack);
}
return null;
}
@@ -3590,7 +3587,7 @@
for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {
- list.add(getStackInfo(stacks.get(ndx)));
+ list.add(getStackInfoLocked(stacks.get(ndx)));
}
}
return list;
@@ -3710,13 +3707,13 @@
}
} break;
case HANDLE_DISPLAY_ADDED: {
- handleDisplayAddedLocked(msg.arg1);
+ handleDisplayAdded(msg.arg1);
} break;
case HANDLE_DISPLAY_CHANGED: {
- handleDisplayChangedLocked(msg.arg1);
+ handleDisplayChanged(msg.arg1);
} break;
case HANDLE_DISPLAY_REMOVED: {
- handleDisplayRemovedLocked(msg.arg1);
+ handleDisplayRemoved(msg.arg1);
} break;
case CONTAINER_CALLBACK_VISIBILITY: {
final ActivityContainer container = (ActivityContainer) msg.obj;
@@ -3851,12 +3848,12 @@
mStackId = stackId;
mStack = new ActivityStack(this, mRecentTasks);
mIdString = "ActivtyContainer{" + mStackId + "}";
- if (DEBUG_STACK) Slog.d(TAG, "Creating " + this);
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "Creating " + this);
}
}
void attachToDisplayLocked(ActivityDisplay activityDisplay) {
- if (DEBUG_STACK) Slog.d(TAG, "attachToDisplayLocked: " + this
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "attachToDisplayLocked: " + this
+ " to display=" + activityDisplay);
mActivityDisplay = activityDisplay;
mStack.mDisplayId = activityDisplay.mDisplayId;
@@ -3934,7 +3931,7 @@
}
protected void detachLocked() {
- if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display="
+ if (DEBUG_STACK) Slog.d(TAG_STACK, "detachLocked: " + this + " from display="
+ mActivityDisplay + " Callers=" + Debug.getCallers(2));
if (mActivityDisplay != null) {
mActivityDisplay.detachActivitiesLocked(mStack);
@@ -4111,8 +4108,8 @@
setSurfaceIfReadyLocked();
- if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
- + virtualActivityDisplay);
+ if (DEBUG_STACK) Slog.d(TAG_STACK,
+ "setSurface: " + this + " to display=" + virtualActivityDisplay);
}
@Override
@@ -4135,7 +4132,7 @@
}
private void setSurfaceIfReadyLocked() {
- if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
+ if (DEBUG_STACK) Slog.v(TAG_STACK, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
" mContainerState=" + mContainerState + " mSurface=" + mSurface);
if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);
@@ -4178,13 +4175,13 @@
}
void attachActivities(ActivityStack stack) {
- if (DEBUG_STACK) Slog.v(TAG, "attachActivities: attaching " + stack + " to displayId="
- + mDisplayId);
+ if (DEBUG_STACK) Slog.v(TAG_STACK,
+ "attachActivities: attaching " + stack + " to displayId=" + mDisplayId);
mStacks.add(stack);
}
void detachActivitiesLocked(ActivityStack stack) {
- if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack
+ if (DEBUG_STACK) Slog.v(TAG_STACK, "detachActivitiesLocked: detaching " + stack
+ " from displayId=" + mDisplayId);
mStacks.remove(stack);
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 7cf3b51..7c921ac 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -89,10 +90,10 @@
int curSchedGroup; // Currently desired scheduling class
int setSchedGroup; // Last set to background scheduling class
int trimMemoryLevel; // Last selected memory trimming level
- int curProcState = -1; // Currently computed process state: ActivityManager.PROCESS_STATE_*
- int repProcState = -1; // Last reported process state
- int setProcState = -1; // Last set process state in process tracker
- int pssProcState = -1; // The proc state we are currently requesting pss for
+ int curProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state
+ int repProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state
+ int setProcState = PROCESS_STATE_NONEXISTENT; // Last set process state in process tracker
+ int pssProcState = PROCESS_STATE_NONEXISTENT; // Currently requesting pss for
boolean serviceb; // Process currently is on the service B list
boolean serviceHighRam; // We are forcing to service B list due to its RAM use
boolean setIsForeground; // Running foreground UI when last set?
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 04912d0..3a20ded 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -16,10 +16,7 @@
package com.android.server.am;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import android.app.ActivityManager;
@@ -44,6 +41,8 @@
*/
class RecentTasks extends ArrayList<TaskRecord> {
private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
+ private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+ private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
// Maximum number recent bitmaps to keep in memory.
private static final int MAX_RECENT_BITMAPS = 3;
@@ -83,8 +82,8 @@
for (int i = size() - 1; i >= 0; --i) {
TaskRecord tr = get(i);
if (tr.userId == userId) {
- if(DEBUG_TASKS) Slog.i(TAG, "remove RecentTask " + tr
- + " when finishing user" + userId);
+ if(DEBUG_TASKS) Slog.i(TAG_TASKS,
+ "remove RecentTask " + tr + " when finishing user" + userId);
remove(i);
tr.removedFromRecents();
}
@@ -170,21 +169,21 @@
continue;
} else {
// Otherwise just not available for now.
- if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG,
+ if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
"Making recent unavailable: " + task);
task.isAvailable = false;
}
} else {
if (!ai.enabled || !ai.applicationInfo.enabled
|| (ai.applicationInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
- if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG,
+ if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
"Making recent unavailable: " + task
+ " (enabled=" + ai.enabled + "/" + ai.applicationInfo.enabled
+ " flags=" + Integer.toHexString(ai.applicationInfo.flags)
+ ")");
task.isAvailable = false;
} else {
- if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG,
+ if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG_RECENTS,
"Making recent available: " + task);
task.isAvailable = true;
}
@@ -210,7 +209,7 @@
top = top.mNextAffiliate;
topIndex--;
}
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding affilliates starting at "
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at "
+ topIndex + " from intial " + taskIndex);
// Find the end of the chain, doing a sanity check along the way.
boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
@@ -218,7 +217,7 @@
TaskRecord prev = top;
while (endIndex < recentsCount) {
TaskRecord cur = get(endIndex);
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: looking at next chain @"
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
+ endIndex + " " + cur);
if (cur == top) {
// Verify start of the chain.
@@ -249,7 +248,7 @@
+ cur.mPrevAffiliate);
sane = false;
}
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: end of chain @" + endIndex);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex);
break;
} else {
// Verify middle of the chain's prev points to a valid item.
@@ -290,12 +289,12 @@
// All looks good, we can just move all of the affiliated tasks
// to the top.
for (int i=topIndex; i<=endIndex; i++) {
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving affiliated " + task
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
+ " from " + i + " to " + (i-topIndex));
TaskRecord cur = remove(i);
add(i - topIndex, cur);
}
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: done moving tasks " + topIndex
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks " + topIndex
+ " to " + endIndex);
return true;
}
@@ -312,19 +311,20 @@
int recentsCount = size();
// Quick case: never add voice sessions.
if (task.voiceSession != null) {
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: not adding voice interaction " + task);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+ "addRecent: not adding voice interaction " + task);
return;
}
// Another quick case: check if the top-most recent task is the same.
if (!isAffiliated && recentsCount > 0 && get(0) == task) {
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: already at top: " + task);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: already at top: " + task);
return;
}
// Another quick case: check if this is part of a set of affiliated
// tasks that are at the top.
if (isAffiliated && recentsCount > 0 && task.inRecents
&& task.mAffiliatedTaskId == get(0).mAffiliatedTaskId) {
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: affiliated " + get(0)
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + get(0)
+ " at top when adding " + task);
return;
}
@@ -341,7 +341,7 @@
remove(taskIndex);
add(0, task);
mService.notifyTaskPersisterLocked(task, false);
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving to top " + task
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
+ " from " + taskIndex);
return;
} else {
@@ -361,7 +361,7 @@
}
}
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: trimming tasks for " + task);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task);
trimForTaskLocked(task, true);
recentsCount = size();
@@ -376,7 +376,7 @@
// If this is a simple non-affiliated task, or we had some failure trying to
// handle it as part of an affilated task, then just place it at the top.
add(0, task);
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding " + task);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task);
} else if (isAffiliated) {
// If this is a new affiliated task, then move all of the affiliated tasks
// to the front and insert this new one.
@@ -398,8 +398,8 @@
// after us in the list, so add at their position.
taskIndex = otherIndex;
}
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: new affiliated task added at "
- + taskIndex + ": " + task);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+ "addRecent: new affiliated task added at " + taskIndex + ": " + task);
add(taskIndex, task);
// Now move everything to the front.
@@ -412,19 +412,19 @@
// everything and then go through our general path of adding a new task.
needAffiliationFix = true;
} else {
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: couldn't find other affiliation "
- + other);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+ "addRecent: couldn't find other affiliation " + other);
needAffiliationFix = true;
}
} else {
- if (DEBUG_RECENTS) Slog.d(TAG,
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
"addRecent: adding affiliated task without next/prev:" + task);
needAffiliationFix = true;
}
}
if (needAffiliationFix) {
- if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: regrouping affiliations");
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations");
cleanupLocked(task.userId);
}
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index d8d361b..82e6d47 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,8 +16,9 @@
package com.android.server.am;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
@@ -56,6 +57,8 @@
final class TaskRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
+ private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+ private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
static final String ATTR_TASKID = "task_id";
private static final String TAG_INTENT = "intent";
@@ -310,8 +313,7 @@
_intent.setSourceBounds(null);
}
}
- if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
- "Setting Intent of " + this + " to " + _intent);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
intent = _intent;
realActivity = _intent != null ? _intent.getComponent() : null;
origActivity = null;
@@ -323,7 +325,7 @@
targetIntent.setComponent(targetComponent);
targetIntent.setSelector(null);
targetIntent.setSourceBounds(null);
- if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
"Setting Intent of " + this + " to target " + targetIntent);
intent = targetIntent;
realActivity = targetComponent;
@@ -346,8 +348,8 @@
if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
// If the activity itself has requested auto-remove, then just always do it.
autoRemoveRecents = true;
- } else if ((intentFlags & (Intent.FLAG_ACTIVITY_NEW_DOCUMENT
- | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) {
+ } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
+ == FLAG_ACTIVITY_NEW_DOCUMENT) {
// If the caller has not asked for the document to be retained, then we may
// want to turn on auto-remove, depending on whether the target has set its
// own document launch mode.
@@ -819,7 +821,7 @@
}
void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
- if (ActivityManagerService.DEBUG_RECENTS) Slog.i(TAG, "Saving task=" + this);
+ if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
if (realActivity != null) {
@@ -879,7 +881,8 @@
for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
- ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) &&
+ ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
+ | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
activityNdx > 0) {
// Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
break;
@@ -1045,7 +1048,7 @@
activities.get(activityNdx).task = task;
}
- if (ActivityManagerService.DEBUG_RECENTS) Slog.d(TAG, "Restored task=" + task);
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
return task;
}
diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java
new file mode 100644
index 0000000..f9b17ed
--- /dev/null
+++ b/services/core/java/com/android/server/camera/CameraService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.camera;
+
+import android.content.Context;
+import android.hardware.ICameraService;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.server.SystemService;
+
+/**
+ * CameraService is the system_server analog to the camera service running in mediaserver.
+ *
+ * @hide
+ */
+public class CameraService extends SystemService {
+
+ /**
+ * This must match the ICameraService.aidl definition
+ */
+ private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
+
+ // Event arguments to use with the camera service notifySystemEvent call:
+ public static final int NO_EVENT = 0; // NOOP
+ public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
+
+ public CameraService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {}
+
+ @Override
+ public void onSwitchUser(int userHandle) {
+ super.onSwitchUser(userHandle);
+
+ /**
+ * Forward the user switch event to the native camera service running in mediaserver.
+ */
+ IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME);
+ if (cameraServiceBinder == null) {
+ return; // Camera service not active, there is no need to evict user clients.
+ }
+ ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
+ try {
+ cameraServiceRaw.notifySystemEvent(USER_SWITCHED, userHandle);
+ } catch (RemoteException e) {
+ // Do nothing, if camera service is dead, there is no need to evict user clients.
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index a415a84..15b68c7 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -571,7 +571,7 @@
}
private static boolean isAccessibleToUser(int uid, int callerUid) {
- return callerUid == android.os.Process.SYSTEM_UID ||
+ return UserHandle.getAppId(callerUid) == android.os.Process.SYSTEM_UID ||
uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING
|| UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
}
diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationKey.java b/services/core/java/com/android/server/pm/IntentFilterVerificationKey.java
new file mode 100644
index 0000000..399b03c
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IntentFilterVerificationKey.java
@@ -0,0 +1,63 @@
+/*
+ * 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.server.pm;
+
+import java.util.Arrays;
+
+/**
+ * This is the key for the map of {@link android.content.pm.IntentFilterVerificationInfo}s
+ * maintained by the {@link com.android.server.pm.PackageManagerService}
+ */
+class IntentFilterVerificationKey {
+ public String domains;
+ public String packageName;
+ public String className;
+
+ public IntentFilterVerificationKey(String[] domains, String packageName, String className) {
+ StringBuilder sb = new StringBuilder();
+ for (String host : domains) {
+ sb.append(host);
+ }
+ this.domains = sb.toString();
+ this.packageName = packageName;
+ this.className = className;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ IntentFilterVerificationKey that = (IntentFilterVerificationKey) o;
+
+ if (domains != null ? !domains.equals(that.domains) : that.domains != null) return false;
+ if (className != null ? !className.equals(that.className) : that.className != null)
+ return false;
+ if (packageName != null ? !packageName.equals(that.packageName) : that.packageName != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = domains != null ? domains.hashCode() : 0;
+ result = 31 * result + (packageName != null ? packageName.hashCode() : 0);
+ result = 31 * result + (className != null ? className.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationResponse.java b/services/core/java/com/android/server/pm/IntentFilterVerificationResponse.java
new file mode 100644
index 0000000..ead399b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IntentFilterVerificationResponse.java
@@ -0,0 +1,43 @@
+/*
+ * 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.server.pm;
+
+
+import java.util.List;
+
+/* package private */ class IntentFilterVerificationResponse {
+ public final int callerUid;
+ public final int code;
+ public final List<String> failedDomains;
+
+ public IntentFilterVerificationResponse(int callerUid, int code, List<String> failedDomains) {
+ this.callerUid = callerUid;
+ this.code = code;
+ this.failedDomains = failedDomains;
+ }
+
+ public String getFailedDomainsString() {
+ StringBuilder sb = new StringBuilder();
+ for (String domain : failedDomains) {
+ if (sb.length() > 0) {
+ sb.append(" ");
+ }
+ sb.append(domain);
+ }
+ return sb.toString();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
new file mode 100644
index 0000000..c09d6ae
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java
@@ -0,0 +1,125 @@
+/*
+ * 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.server.pm;
+
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+public class IntentFilterVerificationState {
+ static final String TAG = IntentFilterVerificationState.class.getName();
+
+ public final static int STATE_UNDEFINED = 0;
+ public final static int STATE_VERIFICATION_PENDING = 1;
+ public final static int STATE_VERIFICATION_SUCCESS = 2;
+ public final static int STATE_VERIFICATION_FAILURE = 3;
+
+ private int mRequiredVerifierUid = 0;
+
+ private int mState;
+
+ private ArrayList<PackageParser.ActivityIntentInfo> mFilters = new ArrayList<>();
+ private ArraySet<String> mHosts = new ArraySet<>();
+ private int mUserId;
+
+ private String mPackageName;
+ private boolean mVerificationComplete;
+
+ public IntentFilterVerificationState(int verifierUid, int userId, String packageName) {
+ mRequiredVerifierUid = verifierUid;
+ mUserId = userId;
+ mPackageName = packageName;
+ mState = STATE_UNDEFINED;
+ mVerificationComplete = false;
+ }
+
+ public void setState(int state) {
+ if (state > STATE_VERIFICATION_FAILURE || state < STATE_UNDEFINED) {
+ mState = STATE_UNDEFINED;
+ } else {
+ mState = state;
+ }
+ }
+
+ public int getState() {
+ return mState;
+ }
+
+ public void setPendingState() {
+ setState(STATE_VERIFICATION_PENDING);
+ }
+
+ public ArrayList<PackageParser.ActivityIntentInfo> getFilters() {
+ return mFilters;
+ }
+
+ public boolean isVerificationComplete() {
+ return mVerificationComplete;
+ }
+
+ public boolean isVerified() {
+ if (mVerificationComplete) {
+ return (mState == STATE_VERIFICATION_SUCCESS);
+ }
+ return false;
+ }
+
+ public int getUserId() {
+ return mUserId;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public String getHostsString() {
+ StringBuilder sb = new StringBuilder();
+ final int count = mHosts.size();
+ for (int i=0; i<count; i++) {
+ if (i > 0) {
+ sb.append(" ");
+ }
+ sb.append(mHosts.valueAt(i));
+ }
+ return sb.toString();
+ }
+
+ public boolean setVerifierResponse(int callerUid, int code) {
+ if (mRequiredVerifierUid == callerUid) {
+ int state = STATE_UNDEFINED;
+ if (code == PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS) {
+ state = STATE_VERIFICATION_SUCCESS;
+ } else if (code == PackageManager.INTENT_FILTER_VERIFICATION_FAILURE) {
+ state = STATE_VERIFICATION_FAILURE;
+ }
+ mVerificationComplete = true;
+ setState(state);
+ return true;
+ }
+ Log.d(TAG, "Cannot set verifier response with callerUid:" + callerUid + " and code:" +
+ code + " as required verifierUid is:" + mRequiredVerifierUid);
+ return false;
+ }
+
+ public void addFilter(PackageParser.ActivityIntentInfo filter) {
+ mFilters.add(filter);
+ mHosts.addAll(filter.getHostsList());
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c7dc74f..b9dfc21 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -44,6 +44,10 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
@@ -59,6 +63,8 @@
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
+import android.Manifest;
+import android.content.pm.IntentFilterVerificationInfo;
import android.util.ArrayMap;
import com.android.internal.R;
@@ -504,6 +510,231 @@
boolean mResolverReplaced = false;
+ private final ComponentName mIntentFilterVerifierComponent;
+ private int mIntentFilterVerificationToken = 0;
+
+ final SparseArray<IntentFilterVerificationState> mIntentFilterVerificationStates
+ = new SparseArray<IntentFilterVerificationState>();
+
+ private interface IntentFilterVerifier<T extends IntentFilter> {
+ boolean addOneIntentFilterVerification(int verifierId, int userId, int verificationId,
+ T filter, String packageName);
+ void startVerifications(int userId);
+ void receiveVerificationResponse(int verificationId);
+ }
+
+ private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> {
+ private Context mContext;
+ private ComponentName mIntentFilterVerifierComponent;
+ private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<Integer>();
+
+ public IntentVerifierProxy(Context context, ComponentName verifierComponent) {
+ mContext = context;
+ mIntentFilterVerifierComponent = verifierComponent;
+ }
+
+ private String getDefaultScheme() {
+ // TODO: replace SCHEME_HTTP with SCHEME_HTTPS
+ return IntentFilter.SCHEME_HTTP;
+ }
+
+ @Override
+ public void startVerifications(int userId) {
+ // Launch verifications requests
+ int count = mCurrentIntentFilterVerifications.size();
+ for (int n=0; n<count; n++) {
+ int verificationId = mCurrentIntentFilterVerifications.get(n);
+ final IntentFilterVerificationState ivs =
+ mIntentFilterVerificationStates.get(verificationId);
+
+ String packageName = ivs.getPackageName();
+ boolean modified = false;
+
+ ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters();
+ final int filterCount = filters.size();
+ for (int m=0; m<filterCount; m++) {
+ PackageParser.ActivityIntentInfo filter = filters.get(m);
+ synchronized (mPackages) {
+ modified = mSettings.createIntentFilterVerificationIfNeededLPw(
+ packageName, filter.getHosts());
+ }
+ }
+ synchronized (mPackages) {
+ if (modified) {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ sendVerificationRequest(userId, verificationId, ivs);
+ }
+ mCurrentIntentFilterVerifications.clear();
+ }
+
+ private void sendVerificationRequest(int userId, int verificationId,
+ IntentFilterVerificationState ivs) {
+
+ Intent verificationIntent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
+ verificationIntent.putExtra(
+ PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID,
+ verificationId);
+ verificationIntent.putExtra(
+ PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME,
+ getDefaultScheme());
+ verificationIntent.putExtra(
+ PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS,
+ ivs.getHostsString());
+ verificationIntent.putExtra(
+ PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME,
+ ivs.getPackageName());
+ verificationIntent.setComponent(mIntentFilterVerifierComponent);
+ verificationIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+
+ UserHandle user = new UserHandle(userId);
+ mContext.sendBroadcastAsUser(verificationIntent, user);
+ Slog.d(TAG, "Sending IntenFilter verification broadcast");
+ }
+
+ public void receiveVerificationResponse(int verificationId) {
+ IntentFilterVerificationState ivs = mIntentFilterVerificationStates.get(verificationId);
+
+ final boolean verified = ivs.isVerified();
+
+ ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters();
+ final int count = filters.size();
+ for (int n=0; n<count; n++) {
+ PackageParser.ActivityIntentInfo filter = filters.get(n);
+ filter.setVerified(verified);
+
+ Slog.d(TAG, "IntentFilter " + filter.toString() + " verified with result:"
+ + verified + " and hosts:" + ivs.getHostsString());
+ }
+
+ mIntentFilterVerificationStates.remove(verificationId);
+
+ final String packageName = ivs.getPackageName();
+ IntentFilterVerificationInfo ivi = null;
+
+ synchronized (mPackages) {
+ ivi = mSettings.getIntentFilterVerificationLPr(packageName);
+ }
+ if (ivi == null) {
+ Slog.w(TAG, "IntentFilterVerificationInfo not found for verificationId:"
+ + verificationId + " packageName:" + packageName);
+ return;
+ }
+ Slog.d(TAG, "Updating IntentFilterVerificationInfo for verificationId: "
+ + verificationId);
+
+ synchronized (mPackages) {
+ if (verified) {
+ ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS);
+ } else {
+ ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK);
+ }
+ scheduleWriteSettingsLocked();
+
+ final int userId = ivs.getUserId();
+ if (userId != UserHandle.USER_ALL) {
+ final int userStatus =
+ mSettings.getIntentFilterVerificationStatusLPr(packageName, userId);
+
+ int updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ boolean needUpdate = false;
+
+ // We cannot override the STATUS_ALWAYS / STATUS_NEVER states if they have
+ // already been set by the User thru the Disambiguation dialog
+ switch (userStatus) {
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
+ if (verified) {
+ updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+ } else {
+ updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
+ }
+ needUpdate = true;
+ break;
+
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
+ if (verified) {
+ updatedStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+ needUpdate = true;
+ }
+ break;
+
+ default:
+ // Nothing to do
+ }
+
+ if (needUpdate) {
+ mSettings.updateIntentFilterVerificationStatusLPw(
+ packageName, updatedStatus, userId);
+ scheduleWritePackageRestrictionsLocked(userId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean addOneIntentFilterVerification(int verifierId, int userId, int verificationId,
+ ActivityIntentInfo filter, String packageName) {
+ if (!(filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+ filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) {
+ Slog.d(TAG, "IntentFilter does not contain HTTP nor HTTPS data scheme");
+ return false;
+ }
+ IntentFilterVerificationState ivs = mIntentFilterVerificationStates.get(verificationId);
+ if (ivs == null) {
+ ivs = createDomainVerificationState(verifierId, userId, verificationId,
+ packageName);
+ }
+ ArrayList<String> hosts = filter.getHostsList();
+ if (!hasValidHosts(hosts)) {
+ return false;
+ }
+ ivs.addFilter(filter);
+ return true;
+ }
+
+ private IntentFilterVerificationState createDomainVerificationState(int verifierId,
+ int userId, int verificationId, String packageName) {
+ IntentFilterVerificationState ivs = new IntentFilterVerificationState(
+ verifierId, userId, packageName);
+ ivs.setPendingState();
+ synchronized (mPackages) {
+ mIntentFilterVerificationStates.append(verificationId, ivs);
+ mCurrentIntentFilterVerifications.add(verificationId);
+ }
+ return ivs;
+ }
+
+ private boolean hasValidHosts(ArrayList<String> hosts) {
+ if (hosts.size() == 0) {
+ Slog.d(TAG, "IntentFilter does not contain any data hosts");
+ return false;
+ }
+ String hostEndBase = null;
+ for (String host : hosts) {
+ String[] hostParts = host.split("\\.");
+ // Should be at minimum a host like "example.com"
+ if (hostParts.length < 2) {
+ Slog.d(TAG, "IntentFilter does not contain a valid data host name: " + host);
+ return false;
+ }
+ // Verify that we have the same ending domain
+ int length = hostParts.length;
+ String hostEnd = hostParts[length - 1] + hostParts[length - 2];
+ if (hostEndBase == null) {
+ hostEndBase = hostEnd;
+ }
+ if (!hostEnd.equalsIgnoreCase(hostEndBase)) {
+ Slog.d(TAG, "IntentFilter does not contain the same data domains");
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ private IntentFilterVerifier mIntentFilterVerifier;
+
// Set of pending broadcasts for aggregating enable/disable of components.
static class PendingPackageBroadcasts {
// for each user id, a map of <package name -> components within that package>
@@ -590,6 +821,8 @@
static final int WRITE_PACKAGE_RESTRICTIONS = 14;
static final int PACKAGE_VERIFIED = 15;
static final int CHECK_PENDING_VERIFICATION = 16;
+ static final int START_INTENT_FILTER_VERIFICATIONS = 17;
+ static final int INTENT_FILTER_VERIFIED = 18;
static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds
@@ -1240,6 +1473,54 @@
break;
}
+ case START_INTENT_FILTER_VERIFICATIONS: {
+ int userId = msg.arg1;
+ int verifierUid = msg.arg2;
+ PackageParser.Package pkg = (PackageParser.Package)msg.obj;
+
+ verifyIntentFiltersIfNeeded(userId, verifierUid, pkg);
+ break;
+ }
+ case INTENT_FILTER_VERIFIED: {
+ final int verificationId = msg.arg1;
+
+ final IntentFilterVerificationState state = mIntentFilterVerificationStates.get(
+ verificationId);
+ if (state == null) {
+ Slog.w(TAG, "Invalid IntentFilter verification token "
+ + verificationId + " received");
+ break;
+ }
+
+ final int userId = state.getUserId();
+
+ Slog.d(TAG, "Processing IntentFilter verification with token:"
+ + verificationId + " and userId:" + userId);
+
+ final IntentFilterVerificationResponse response =
+ (IntentFilterVerificationResponse) msg.obj;
+
+ state.setVerifierResponse(response.callerUid, response.code);
+
+ Slog.d(TAG, "IntentFilter verification with token:" + verificationId
+ + " and userId:" + userId
+ + " is settings verifier response with response code:"
+ + response.code);
+
+ if (response.code == PackageManager.INTENT_FILTER_VERIFICATION_FAILURE) {
+ Slog.d(TAG, "Domains failing verification: "
+ + response.getFailedDomainsString());
+ }
+
+ if (state.isVerificationComplete()) {
+ mIntentFilterVerifier.receiveVerificationResponse(verificationId);
+ } else {
+ Slog.d(TAG, "IntentFilter verification with token:" + verificationId
+ + " was not said to be complete");
+ }
+
+ break;
+ }
}
}
}
@@ -1851,11 +2132,16 @@
SystemClock.uptimeMillis());
mRequiredVerifierPackage = getRequiredVerifierLPr();
+
+ mInstallerService = new PackageInstallerService(context, this, mAppInstallDir);
+
+ mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
+ mIntentFilterVerifier = new IntentVerifierProxy(mContext,
+ mIntentFilterVerifierComponent);
+
} // synchronized (mPackages)
} // synchronized (mInstallLock)
- mInstallerService = new PackageInstallerService(context, this, mAppInstallDir);
-
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
// tidy.
@@ -1909,6 +2195,46 @@
return requiredVerifier;
}
+ private ComponentName getIntentFilterVerifierComponentNameLPr() {
+ final Intent verification = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
+ final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
+ PackageManager.GET_DISABLED_COMPONENTS, 0 /* userId */);
+
+ ComponentName verifierComponentName = null;
+
+ int priority = -1000;
+ final int N = receivers.size();
+ for (int i = 0; i < N; i++) {
+ final ResolveInfo info = receivers.get(i);
+
+ if (info.activityInfo == null) {
+ continue;
+ }
+
+ final String packageName = info.activityInfo.packageName;
+
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps == null) {
+ continue;
+ }
+
+ if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
+ packageName, UserHandle.USER_OWNER) != PackageManager.PERMISSION_GRANTED) {
+ continue;
+ }
+
+ // Select the IntentFilterVerifier with the highest priority
+ if (priority < info.priority) {
+ priority = info.priority;
+ verifierComponentName = new ComponentName(packageName, info.activityInfo.name);
+ Slog.d(TAG, "Selecting IntentFilterVerifier: " + verifierComponentName +
+ " with priority: " + info.priority);
+ }
+ }
+
+ return verifierComponentName;
+ }
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -3532,14 +3858,20 @@
resolveInfo = queryCrossProfileIntents(
matchingFilters, intent, resolvedType, flags, userId);
- // Check for results in the current profile.
+ // Check for results in the current profile. Adding GET_RESOLVED_FILTER flags
+ // as we need it later
List<ResolveInfo> result = mActivities.queryIntent(
intent, resolvedType, flags, userId);
if (resolveInfo != null) {
result.add(resolveInfo);
Collections.sort(result, mResolvePrioritySorter);
}
- return filterIfNotPrimaryUser(result, userId);
+ result = filterIfNotPrimaryUser(result, userId);
+ if (result.size() > 1) {
+ return filterCandidatesWithDomainPreferedActivitiesLPw(result);
+ }
+
+ return result;
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
@@ -3570,6 +3902,49 @@
return resolveInfos;
}
+ private List<ResolveInfo> filterCandidatesWithDomainPreferedActivitiesLPw(
+ List<ResolveInfo> candidates) {
+ if (DEBUG_PREFERRED) {
+ Slog.v("TAG", "Filtering results with prefered activities. Candidates count: " +
+ candidates.size());
+ }
+ final int userId = UserHandle.getCallingUserId();
+ ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>(candidates);
+ synchronized (mPackages) {
+ final int count = result.size();
+ for (int n = count-1; n >= 0; n--) {
+ ResolveInfo info = result.get(n);
+ if (!info.filterNeedsVerification) {
+ continue;
+ }
+ String packageName = info.activityInfo.packageName;
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps != null) {
+ // Try to get the status from User settings first
+ int status = ps.getDomainVerificationStatusForUser(userId);
+ // if none available, get the master status
+ if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+ if (ps.getIntentFilterVerificationInfo() != null) {
+ status = ps.getIntentFilterVerificationInfo().getStatus();
+ }
+ }
+ if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
+ result.clear();
+ result.add(info);
+ // We break the for loop as we are good to go
+ break;
+ } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
+ result.remove(n);
+ }
+ }
+ }
+ }
+ if (DEBUG_PREFERRED) {
+ Slog.v("TAG", "Filtered results with prefered activities. New candidates count: " +
+ result.size());
+ }
+ return result;
+ }
private ResolveInfo querySkipCurrentProfileIntents(
List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
@@ -7444,6 +7819,9 @@
if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
res.filter = info;
}
+ if (info != null) {
+ res.filterNeedsVerification = info.needsVerification();
+ }
res.priority = info.getPriority();
res.preferredOrder = activity.owner.mPreferredOrder;
//System.out.println("Result: " + res.activityInfo.className +
@@ -7666,8 +8044,6 @@
}
res.priority = info.getPriority();
res.preferredOrder = service.owner.mPreferredOrder;
- //System.out.println("Result: " + res.activityInfo.className +
- // " = " + res.priority);
res.match = match;
res.isDefault = info.hasDefault;
res.labelRes = info.labelRes;
@@ -8544,6 +8920,45 @@
android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 1;
}
+ @Override
+ public void verifyIntentFilter(int id, int verificationCode, List<String> outFailedDomains)
+ throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
+ "Only intentfilter verification agents can verify applications");
+
+ final Message msg = mHandler.obtainMessage(INTENT_FILTER_VERIFIED);
+ final IntentFilterVerificationResponse response = new IntentFilterVerificationResponse(
+ Binder.getCallingUid(), verificationCode, outFailedDomains);
+ msg.arg1 = id;
+ msg.obj = response;
+ mHandler.sendMessage(msg);
+ }
+
+ @Override
+ public int getIntentVerificationStatus(String packageName, int userId) {
+ synchronized (mPackages) {
+ return mSettings.getIntentFilterVerificationStatusLPr(packageName, userId);
+ }
+ }
+
+ @Override
+ public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+ boolean result = false;
+ synchronized (mPackages) {
+ result = mSettings.updateIntentFilterVerificationStatusLPw(packageName, status, userId);
+ }
+ scheduleWritePackageRestrictionsLocked(userId);
+ return result;
+ }
+
+ @Override
+ public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
+ synchronized (mPackages) {
+ return mSettings.getIntentFilterVerificationsLPr(packageName);
+ }
+ }
+
/**
* Get the "allow unknown sources" setting.
*
@@ -10708,6 +11123,8 @@
return;
}
+ startIntentFilterVerifications(args.user.getIdentifier(), pkg);
+
if (replace) {
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
installerPackageName, res);
@@ -10723,6 +11140,86 @@
}
}
+ private void startIntentFilterVerifications(int userId, PackageParser.Package pkg) {
+ if (mIntentFilterVerifierComponent == null) {
+ Slog.d(TAG, "No IntentFilter verification will not be done as "
+ + "there is no IntentFilterVerifier available!");
+ return;
+ }
+
+ final int verifierUid = getPackageUid(
+ mIntentFilterVerifierComponent.getPackageName(),
+ (userId == UserHandle.USER_ALL) ? UserHandle.USER_OWNER : userId);
+
+ mHandler.removeMessages(START_INTENT_FILTER_VERIFICATIONS);
+ final Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
+ msg.obj = pkg;
+ msg.arg1 = userId;
+ msg.arg2 = verifierUid;
+
+ mHandler.sendMessage(msg);
+ }
+
+ private void verifyIntentFiltersIfNeeded(int userId, int verifierUid,
+ PackageParser.Package pkg) {
+ int size = pkg.activities.size();
+ if (size == 0) {
+ Slog.d(TAG, "No activity, so no need to verify any IntentFilter!");
+ return;
+ }
+
+ Slog.d(TAG, "Checking for userId:" + userId + " if any IntentFilter from the " + size
+ + " Activities needs verification ...");
+
+ final int verificationId = mIntentFilterVerificationToken++;
+ int count = 0;
+ synchronized (mPackages) {
+ for (PackageParser.Activity a : pkg.activities) {
+ for (ActivityIntentInfo filter : a.intents) {
+ boolean needFilterVerification = filter.needsVerification() &&
+ !filter.isVerified();
+ if (needFilterVerification && needNetworkVerificationLPr(filter)) {
+ Slog.d(TAG, "Verification needed for IntentFilter:" + filter.toString());
+ mIntentFilterVerifier.addOneIntentFilterVerification(
+ verifierUid, userId, verificationId, filter, pkg.packageName);
+ count++;
+ } else {
+ Slog.d(TAG, "No verification needed for IntentFilter:" + filter.toString());
+ }
+ }
+ }
+ }
+
+ if (count > 0) {
+ mIntentFilterVerifier.startVerifications(userId);
+ Slog.d(TAG, "Started " + count + " IntentFilter verification"
+ + (count > 1 ? "s" : "") + " for userId:" + userId + "!");
+ } else {
+ Slog.d(TAG, "No need to start any IntentFilter verification!");
+ }
+ }
+
+ private boolean needNetworkVerificationLPr(ActivityIntentInfo filter) {
+ final ComponentName cn = filter.activity.getComponentName();
+ final String packageName = cn.getPackageName();
+
+ IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr(
+ packageName);
+ if (ivi == null) {
+ return true;
+ }
+ int status = ivi.getStatus();
+ switch (status) {
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
+ case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
+ return true;
+
+ default:
+ // Nothing to do
+ return false;
+ }
+ }
+
private static boolean isMultiArch(PackageSetting ps) {
return (ps.pkgFlags & ApplicationInfo.FLAG_MULTIARCH) != 0;
}
@@ -11066,6 +11563,7 @@
}
}
clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
+ clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
}
// make sure to preserve per-user disabled state if this removal was just
// a downgrade of a system app to the factory package
@@ -11294,8 +11792,8 @@
true, //notLaunched
false, //hidden
null, null, null,
- false // blockUninstall
- );
+ false, // blockUninstall
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
if (!isSystemApp(ps)) {
if (ps.isAnyInstalled(sUserManager.getUserIds())) {
// Other user still have this package installed, so all
@@ -11918,6 +12416,19 @@
return changed;
}
+ /** This method takes a specific user id as well as UserHandle.USER_ALL. */
+ void clearIntentFilterVerificationsLPw(String packageName, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ mSettings.removeIntentFilterVerificationLPw(packageName, sUserManager.getUserIds());
+ for (int oneUserId : sUserManager.getUserIds()) {
+ scheduleWritePackageRestrictionsLocked(oneUserId);
+ }
+ } else {
+ mSettings.removeIntentFilterVerificationLPw(packageName, userId);
+ scheduleWritePackageRestrictionsLocked(userId);
+ }
+ }
+
@Override
public void resetPreferredActivities(int userId) {
/* TODO: Actually use userId. Why is it being passed in? */
@@ -12428,6 +12939,8 @@
public static final int DUMP_KEYSETS = 1 << 11;
public static final int DUMP_VERSION = 1 << 12;
public static final int DUMP_INSTALLS = 1 << 13;
+ public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 14;
+ public static final int DUMP_DOMAIN_PREFERRED = 1 << 15;
public static final int OPTION_SHOW_FILTERS = 1 << 0;
@@ -12533,6 +13046,8 @@
pw.println(" write: write current settings now");
pw.println(" <package.name>: info about given package");
pw.println(" installs: details about install sessions");
+ pw.println(" d[omain-preferred-apps]: print domains preferred apps");
+ pw.println(" i[ntent-filter-verifiers]|ifv: print intent filter verifier info");
return;
} else if ("--checkin".equals(opt)) {
checkin = true;
@@ -12569,6 +13084,8 @@
fullPreferred = true;
opti++;
}
+ } else if ("d".equals(cmd) || "domain-preferred-apps".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_DOMAIN_PREFERRED);
} else if ("p".equals(cmd) || "packages".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_PACKAGES);
} else if ("s".equals(cmd) || "shared-users".equals(cmd)) {
@@ -12579,6 +13096,9 @@
dumpState.setDump(DumpState.DUMP_MESSAGES);
} else if ("v".equals(cmd) || "verifiers".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_VERIFIERS);
+ } else if ("i".equals(cmd) || "ifv".equals(cmd)
+ || "intent-filter-verifiers".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_INTENT_FILTER_VERIFIERS);
} else if ("version".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_VERSION);
} else if ("k".equals(cmd) || "keysets".equals(cmd)) {
@@ -12634,6 +13154,29 @@
}
}
+ if (dumpState.isDumping(DumpState.DUMP_INTENT_FILTER_VERIFIERS) &&
+ packageName == null) {
+ if (mIntentFilterVerifierComponent != null) {
+ String verifierPackageName = mIntentFilterVerifierComponent.getPackageName();
+ if (!checkin) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Intent Filter Verifier:");
+ pw.print(" Using: ");
+ pw.print(verifierPackageName);
+ pw.print(" (uid=");
+ pw.print(getPackageUid(verifierPackageName, 0));
+ pw.println(")");
+ } else if (verifierPackageName != null) {
+ pw.print("ifv,"); pw.print(verifierPackageName);
+ pw.print(","); pw.println(getPackageUid(verifierPackageName, 0));
+ }
+ } else {
+ pw.println();
+ pw.println("No Intent Filter Verifier available!");
+ }
+ }
+
if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
boolean printedHeader = false;
final Iterator<String> it = mSharedLibraries.keySet().iterator();
@@ -12753,6 +13296,65 @@
}
}
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
+ pw.println();
+ int count = mSettings.mPackages.size();
+ if (count == 0) {
+ pw.println("No domain preferred apps!");
+ pw.println();
+ } else {
+ final String prefix = " ";
+ Collection<PackageSetting> allPackageSettings = mSettings.mPackages.values();
+ if (allPackageSettings.size() == 0) {
+ pw.println("No domain preferred apps!");
+ pw.println();
+ } else {
+ pw.println("Domain preferred apps status:");
+ pw.println();
+ count = 0;
+ for (PackageSetting ps : allPackageSettings) {
+ IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
+ if (ivi == null || ivi.getPackageName() == null) continue;
+ pw.println(prefix + "Package Name: " + ivi.getPackageName());
+ pw.println(prefix + "Domains: " + ivi.getDomainsString());
+ pw.println(prefix + "Status: " + ivi.getStatusString());
+ pw.println();
+ count++;
+ }
+ if (count == 0) {
+ pw.println(prefix + "No domain preferred app status!");
+ pw.println();
+ }
+ for (int userId : sUserManager.getUserIds()) {
+ pw.println("Domain preferred apps for User " + userId + ":");
+ pw.println();
+ count = 0;
+ for (PackageSetting ps : allPackageSettings) {
+ IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
+ if (ivi == null || ivi.getPackageName() == null) {
+ continue;
+ }
+ final int status = ps.getDomainVerificationStatusForUser(userId);
+ if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+ continue;
+ }
+ pw.println(prefix + "Package Name: " + ivi.getPackageName());
+ pw.println(prefix + "Domains: " + ivi.getDomainsString());
+ String statusStr = IntentFilterVerificationInfo.
+ getStatusStringFromValue(status);
+ pw.println(prefix + "Status: " + statusStr);
+ pw.println();
+ count++;
+ }
+ if (count == 0) {
+ pw.println(prefix + "No domain preferred apps!");
+ pw.println();
+ }
+ }
+ }
+ }
+ }
+
if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
mSettings.dumpPermissionsLPr(pw, packageName, dumpState);
if (packageName == null) {
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 35df33b..daa6d64 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -20,6 +20,8 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.PackageUserState;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -108,6 +110,9 @@
/* package name of the app that installed this package */
String installerPackageName;
+
+ IntentFilterVerificationInfo verificationInfo;
+
PackageSettingBase(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
@@ -199,7 +204,7 @@
*/
public void copyFrom(PackageSettingBase base) {
setPermissionsUpdatedForUserIds(base.getPermissionsUpdatedForUserIds());
- getPermissionsState().copyFrom(base.getPermissionsState());
+ mPermissionsState.copyFrom(base.mPermissionsState);
primaryCpuAbiString = base.primaryCpuAbiString;
secondaryCpuAbiString = base.secondaryCpuAbiString;
cpuAbiOverrideString = base.cpuAbiOverrideString;
@@ -214,6 +219,7 @@
}
installStatus = base.installStatus;
keySetData = base.keySetData;
+ verificationInfo = base.verificationInfo;
}
private PackageUserState modifyUserState(int userId) {
@@ -317,7 +323,7 @@
void setUserState(int userId, int enabled, boolean installed, boolean stopped,
boolean notLaunched, boolean hidden,
String lastDisableAppCaller, ArraySet<String> enabledComponents,
- ArraySet<String> disabledComponents, boolean blockUninstall) {
+ ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState) {
PackageUserState state = modifyUserState(userId);
state.enabled = enabled;
state.installed = installed;
@@ -328,6 +334,7 @@
state.enabledComponents = enabledComponents;
state.disabledComponents = disabledComponents;
state.blockUninstall = blockUninstall;
+ state.domainVerificationStatus = domainVerifState;
}
ArraySet<String> getEnabledComponents(int userId) {
@@ -415,4 +422,25 @@
void removeUser(int userId) {
userState.delete(userId);
}
+
+ public IntentFilterVerificationInfo getIntentFilterVerificationInfo() {
+ return verificationInfo;
+ }
+
+ public void setIntentFilterVerificationInfo(IntentFilterVerificationInfo info) {
+ verificationInfo = info;
+ }
+
+ public int getDomainVerificationStatusForUser(int userId) {
+ return readUserState(userId).domainVerificationStatus;
+ }
+
+ public void setDomainVerificationStatusForUser(int status, int userId) {
+ modifyUserState(userId).domainVerificationStatus = status;
+ }
+
+ public void clearDomainVerificationStatusForUser(int userId) {
+ modifyUserState(userId).domainVerificationStatus =
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ }
}
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 3a7b6ee..0c7f79d 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -24,7 +24,7 @@
int pkgFlags;
int pkgPrivateFlags;
- private final PermissionsState mPermissionsState;
+ protected final PermissionsState mPermissionsState;
private int[] mPermissionsUpdatedForUserIds = PermissionsState.USERS_NONE;
SettingBase(int pkgFlags, int pkgPrivateFlags) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 8f185ec..dd58813 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -22,11 +22,13 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.PACKAGE_INFO_GID;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
+import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Binder;
@@ -41,6 +43,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.util.AtomicFile;
+import android.text.TextUtils;
import android.util.LogPrinter;
import android.util.SparseBooleanArray;
@@ -88,6 +91,7 @@
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
@@ -160,6 +164,7 @@
"persistent-preferred-activities";
static final String TAG_CROSS_PROFILE_INTENT_FILTERS =
"crossProfile-intent-filters";
+ public static final String TAG_DOMAIN_VERIFICATION = "domain-verification";
private static final String ATTR_NAME = "name";
private static final String ATTR_USER = "user";
@@ -174,6 +179,7 @@
private static final String ATTR_HIDDEN = "hidden";
private static final String ATTR_INSTALLED = "inst";
private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
+ private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
private final Object mLock;
@@ -590,8 +596,8 @@
true, // notLaunched
false, // hidden
null, null, null,
- false // blockUninstall
- );
+ false, // blockUninstall
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
writePackageRestrictionsLPr(user.id);
}
}
@@ -865,7 +871,7 @@
if (mOtherUserIds.get(uid) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared id: " + uid
- + " name=" + name);
+ + " name=" + name);
return false;
}
mOtherUserIds.put(uid, obj);
@@ -931,6 +937,96 @@
return cpir;
}
+ /**
+ * The following functions suppose that you have a lock for managing access to the
+ * mIntentFiltersVerifications map.
+ */
+
+ /* package protected */
+ IntentFilterVerificationInfo getIntentFilterVerificationLPr(String packageName) {
+ PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ Slog.w(PackageManagerService.TAG, "No package known for name: " + packageName);
+ return null;
+ }
+ return ps.getIntentFilterVerificationInfo();
+ }
+
+ /* package protected */
+ boolean createIntentFilterVerificationIfNeededLPw(String packageName, String[] domains) {
+ PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ Slog.w(PackageManagerService.TAG, "No package known for name: " + packageName);
+ return false;
+ }
+ if (ps.getIntentFilterVerificationInfo() == null) {
+ IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(packageName, domains);
+ ps.setIntentFilterVerificationInfo(ivi);
+ return false;
+ }
+ return true;
+ }
+
+ int getIntentFilterVerificationStatusLPr(String packageName, int userId) {
+ PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ Slog.w(PackageManagerService.TAG, "No package known for name: " + packageName);
+ return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+ }
+ int status = ps.getDomainVerificationStatusForUser(userId);
+ if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+ if (ps.getIntentFilterVerificationInfo() != null) {
+ status = ps.getIntentFilterVerificationInfo().getStatus();
+ }
+ }
+ return status;
+ }
+
+ boolean updateIntentFilterVerificationStatusLPw(String packageName, int status, int userId) {
+ PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ Slog.w(PackageManagerService.TAG, "No package known for name: " + packageName);
+ return false;
+ }
+ ps.setDomainVerificationStatusForUser(status, userId);
+ return true;
+ }
+
+ /**
+ * Used for dump. Should be read only.
+ */
+ List<IntentFilterVerificationInfo> getIntentFilterVerificationsLPr(
+ String packageName) {
+ if (packageName == null) {
+ return Collections.<IntentFilterVerificationInfo>emptyList();
+ }
+ ArrayList<IntentFilterVerificationInfo> result = new ArrayList<>();
+ for (PackageSetting ps : mPackages.values()) {
+ IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
+ if (ivi == null || TextUtils.isEmpty(ivi.getPackageName()) ||
+ !ivi.getPackageName().equalsIgnoreCase(packageName)) {
+ continue;
+ }
+ result.add(ivi);
+ }
+ return result;
+ }
+
+ void removeIntentFilterVerificationLPw(String packageName, int userId) {
+ PackageSetting ps = mPackages.get(packageName);
+ if (ps == null) {
+ Slog.w(PackageManagerService.TAG, "No package known for name: " + packageName);
+ return;
+ }
+ ps.clearDomainVerificationStatusForUser(userId);
+ }
+
+ void removeIntentFilterVerificationLPw(String packageName, int[] userIds) {
+ for (int userId : userIds) {
+ removeIntentFilterVerificationLPw(packageName, userId);
+ }
+ }
+
private File getUserPackagesStateFile(int userId) {
// TODO: Implement a cleaner solution when adding tests.
// This instead of Environment.getUserSystemDirectory(userId) to support testing.
@@ -1083,6 +1179,25 @@
}
}
+ private void readDomainVerificationLPw(XmlPullParser parser, PackageSettingBase packageSetting)
+ throws XmlPullParserException, IOException {
+ IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(parser);
+ packageSetting.setIntentFilterVerificationInfo(ivi);
+ Log.d(TAG, "Read domain verification for package:" + ivi.getPackageName());
+ }
+
+ void writeDomainVerificationsLPr(XmlSerializer serializer, String packageName,
+ IntentFilterVerificationInfo verificationInfo)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ if (verificationInfo != null && verificationInfo.getPackageName() != null) {
+ serializer.startTag(null, TAG_DOMAIN_VERIFICATION);
+ verificationInfo.writeToXml(serializer);
+ Log.d(TAG, "Wrote domain verification for package: "
+ + verificationInfo.getPackageName());
+ serializer.endTag(null, TAG_DOMAIN_VERIFICATION);
+ }
+ }
+
void readPackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -1127,8 +1242,8 @@
false, // notLaunched
false, // hidden
null, null, null,
- false // blockUninstall
- );
+ false, // blockUninstall
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
}
return;
}
@@ -1197,6 +1312,12 @@
final boolean blockUninstall = blockUninstallStr == null
? false : Boolean.parseBoolean(blockUninstallStr);
+ final String verifStateStr =
+ parser.getAttributeValue(null, ATTR_DOMAIN_VERIFICATON_STATE);
+ final int verifState = (verifStateStr == null) ?
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED :
+ Integer.parseInt(verifStateStr);
+
ArraySet<String> enabledComponents = null;
ArraySet<String> disabledComponents = null;
@@ -1217,7 +1338,8 @@
}
ps.setUserState(userId, enabled, installed, stopped, notLaunched, hidden,
- enabledCaller, enabledComponents, disabledComponents, blockUninstall);
+ enabledCaller, enabledComponents, disabledComponents, blockUninstall,
+ verifState);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -1364,7 +1486,9 @@
&& ustate.enabledComponents.size() > 0)
|| (ustate.disabledComponents != null
&& ustate.disabledComponents.size() > 0)
- || ustate.blockUninstall) {
+ || ustate.blockUninstall
+ || (ustate.domainVerificationStatus !=
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED)) {
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, pkg.name);
if (DEBUG_MU) Log.i(TAG, " pkg=" + pkg.name + ", state=" + ustate.enabled);
@@ -1392,6 +1516,11 @@
ustate.lastDisableAppCaller);
}
}
+ if (ustate.domainVerificationStatus !=
+ PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+ serializer.attribute(null, ATTR_DOMAIN_VERIFICATON_STATE,
+ Integer.toString(ustate.domainVerificationStatus));
+ }
if (ustate.enabledComponents != null
&& ustate.enabledComponents.size() > 0) {
serializer.startTag(null, TAG_ENABLED_COMPONENTS);
@@ -1418,9 +1547,7 @@
}
writePreferredActivitiesLPr(serializer, userId, true);
-
writePersistentPreferredActivitiesLPr(serializer, userId);
-
writeCrossProfileIntentFiltersLPr(serializer, userId);
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
@@ -1933,6 +2060,7 @@
writeSigningKeySetsLPr(serializer, pkg.keySetData);
writeUpgradeKeySetsLPr(serializer, pkg.keySetData);
writeKeySetAliasesLPr(serializer, pkg.keySetData);
+ writeDomainVerificationsLPr(serializer, pkg.name, pkg.verificationInfo);
serializer.endTag(null, "package");
}
@@ -2109,7 +2237,8 @@
// TODO: check whether this is okay! as it is very
// similar to how preferred-activities are treated
readCrossProfileIntentFiltersLPw(parser, 0);
- } else if (tagName.equals("updated-package")) {
+ }
+ else if (tagName.equals("updated-package")) {
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
String name = parser.getAttributeValue(null, ATTR_NAME);
@@ -3024,6 +3153,8 @@
long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
String alias = parser.getAttributeValue(null, "alias");
packageSetting.keySetData.addDefinedKeySet(id, alias);
+ } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
+ readDomainVerificationLPw(parser, packageSetting);
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unknown element under <package>: " + parser.getName());
@@ -3388,7 +3519,7 @@
return false;
}
- private List<UserInfo> getAllUsers() {
+ List<UserInfo> getAllUsers() {
long id = Binder.clearCallingIdentity();
try {
return UserManagerService.getInstance().getUsers(false);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8cc9d19..5e58cd9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -36,6 +36,7 @@
import android.os.IUserManager;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -49,9 +50,11 @@
import android.util.TimeUtils;
import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -71,6 +74,8 @@
import java.util.ArrayList;
import java.util.List;
+import libcore.io.IoUtils;
+
public class UserManagerService extends IUserManager.Stub {
private static final String LOG_TAG = "UserManagerService";
@@ -107,6 +112,8 @@
private static final String ATTR_TYPE_STRING = "s";
private static final String ATTR_TYPE_BOOLEAN = "b";
private static final String ATTR_TYPE_INTEGER = "i";
+ private static final String ATTR_TYPE_BUNDLE = "B";
+ private static final String ATTR_TYPE_BUNDLE_ARRAY = "BA";
private static final String USER_INFO_DIR = "system" + File.separator + "users";
private static final String USER_LIST_FILENAME = "userlist.xml";
@@ -1672,124 +1679,168 @@
private Bundle readApplicationRestrictionsLocked(String packageName,
int userId) {
+ AtomicFile restrictionsFile =
+ new AtomicFile(new File(Environment.getUserSystemDirectory(userId),
+ packageToRestrictionsFileName(packageName)));
+ return readApplicationRestrictionsLocked(restrictionsFile);
+ }
+
+ @VisibleForTesting
+ static Bundle readApplicationRestrictionsLocked(AtomicFile restrictionsFile) {
final Bundle restrictions = new Bundle();
- final ArrayList<String> values = new ArrayList<String>();
+ final ArrayList<String> values = new ArrayList<>();
FileInputStream fis = null;
try {
- AtomicFile restrictionsFile =
- new AtomicFile(new File(Environment.getUserSystemDirectory(userId),
- packageToRestrictionsFileName(packageName)));
fis = restrictionsFile.openRead();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(fis, null);
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- ;
- }
-
- if (type != XmlPullParser.START_TAG) {
+ XmlUtils.nextElement(parser);
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
Slog.e(LOG_TAG, "Unable to read restrictions file "
+ restrictionsFile.getBaseFile());
return restrictions;
}
-
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
- String key = parser.getAttributeValue(null, ATTR_KEY);
- String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
- String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
- if (multiple != null) {
- values.clear();
- int count = Integer.parseInt(multiple);
- while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (type == XmlPullParser.START_TAG
- && parser.getName().equals(TAG_VALUE)) {
- values.add(parser.nextText().trim());
- count--;
- }
- }
- String [] valueStrings = new String[values.size()];
- values.toArray(valueStrings);
- restrictions.putStringArray(key, valueStrings);
- } else {
- String value = parser.nextText().trim();
- if (ATTR_TYPE_BOOLEAN.equals(valType)) {
- restrictions.putBoolean(key, Boolean.parseBoolean(value));
- } else if (ATTR_TYPE_INTEGER.equals(valType)) {
- restrictions.putInt(key, Integer.parseInt(value));
- } else {
- restrictions.putString(key, value);
- }
- }
- }
+ while (parser.next() != XmlPullParser.END_DOCUMENT) {
+ readEntry(restrictions, values, parser);
}
- } catch (IOException ioe) {
- } catch (XmlPullParserException pe) {
+ } catch (IOException|XmlPullParserException e) {
+ Log.w(LOG_TAG, "Error parsing " + restrictionsFile.getBaseFile(), e);
} finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {
- }
- }
+ IoUtils.closeQuietly(fis);
}
return restrictions;
}
+ private static void readEntry(Bundle restrictions, ArrayList<String> values,
+ XmlPullParser parser) throws XmlPullParserException, IOException {
+ int type = parser.getEventType();
+ if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
+ String key = parser.getAttributeValue(null, ATTR_KEY);
+ String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
+ String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
+ if (multiple != null) {
+ values.clear();
+ int count = Integer.parseInt(multiple);
+ while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type == XmlPullParser.START_TAG
+ && parser.getName().equals(TAG_VALUE)) {
+ values.add(parser.nextText().trim());
+ count--;
+ }
+ }
+ String [] valueStrings = new String[values.size()];
+ values.toArray(valueStrings);
+ restrictions.putStringArray(key, valueStrings);
+ } else if (ATTR_TYPE_BUNDLE.equals(valType)) {
+ restrictions.putBundle(key, readBundleEntry(parser, values));
+ } else if (ATTR_TYPE_BUNDLE_ARRAY.equals(valType)) {
+ final int outerDepth = parser.getDepth();
+ ArrayList<Bundle> bundleList = new ArrayList<>();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ Bundle childBundle = readBundleEntry(parser, values);
+ bundleList.add(childBundle);
+ }
+ restrictions.putParcelableArray(key,
+ bundleList.toArray(new Bundle[bundleList.size()]));
+ } else {
+ String value = parser.nextText().trim();
+ if (ATTR_TYPE_BOOLEAN.equals(valType)) {
+ restrictions.putBoolean(key, Boolean.parseBoolean(value));
+ } else if (ATTR_TYPE_INTEGER.equals(valType)) {
+ restrictions.putInt(key, Integer.parseInt(value));
+ } else {
+ restrictions.putString(key, value);
+ }
+ }
+ }
+ }
+
+ private static Bundle readBundleEntry(XmlPullParser parser, ArrayList<String> values)
+ throws IOException, XmlPullParserException {
+ Bundle childBundle = new Bundle();
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ readEntry(childBundle, values, parser);
+ }
+ return childBundle;
+ }
+
private void writeApplicationRestrictionsLocked(String packageName,
Bundle restrictions, int userId) {
- FileOutputStream fos = null;
AtomicFile restrictionsFile = new AtomicFile(
new File(Environment.getUserSystemDirectory(userId),
packageToRestrictionsFileName(packageName)));
+ writeApplicationRestrictionsLocked(restrictions, restrictionsFile);
+ }
+
+ @VisibleForTesting
+ static void writeApplicationRestrictionsLocked(Bundle restrictions,
+ AtomicFile restrictionsFile) {
+ FileOutputStream fos = null;
try {
fos = restrictionsFile.startWrite();
final BufferedOutputStream bos = new BufferedOutputStream(fos);
- // XmlSerializer serializer = XmlUtils.serializerInstance();
final XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(bos, "utf-8");
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, TAG_RESTRICTIONS);
-
- for (String key : restrictions.keySet()) {
- Object value = restrictions.get(key);
- serializer.startTag(null, TAG_ENTRY);
- serializer.attribute(null, ATTR_KEY, key);
-
- if (value instanceof Boolean) {
- serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BOOLEAN);
- serializer.text(value.toString());
- } else if (value instanceof Integer) {
- serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_INTEGER);
- serializer.text(value.toString());
- } else if (value == null || value instanceof String) {
- serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING);
- serializer.text(value != null ? (String) value : "");
- } else {
- serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING_ARRAY);
- String[] values = (String[]) value;
- serializer.attribute(null, ATTR_MULTIPLE, Integer.toString(values.length));
- for (String choice : values) {
- serializer.startTag(null, TAG_VALUE);
- serializer.text(choice != null ? choice : "");
- serializer.endTag(null, TAG_VALUE);
- }
- }
- serializer.endTag(null, TAG_ENTRY);
- }
-
+ writeBundle(restrictions, serializer);
serializer.endTag(null, TAG_RESTRICTIONS);
serializer.endDocument();
restrictionsFile.finishWrite(fos);
} catch (Exception e) {
restrictionsFile.failWrite(fos);
- Slog.e(LOG_TAG, "Error writing application restrictions list");
+ Slog.e(LOG_TAG, "Error writing application restrictions list", e);
+ }
+ }
+
+ private static void writeBundle(Bundle restrictions, XmlSerializer serializer)
+ throws IOException {
+ for (String key : restrictions.keySet()) {
+ Object value = restrictions.get(key);
+ serializer.startTag(null, TAG_ENTRY);
+ serializer.attribute(null, ATTR_KEY, key);
+
+ if (value instanceof Boolean) {
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BOOLEAN);
+ serializer.text(value.toString());
+ } else if (value instanceof Integer) {
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_INTEGER);
+ serializer.text(value.toString());
+ } else if (value == null || value instanceof String) {
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING);
+ serializer.text(value != null ? (String) value : "");
+ } else if (value instanceof Bundle) {
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BUNDLE);
+ writeBundle((Bundle) value, serializer);
+ } else if (value instanceof Parcelable[]) {
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BUNDLE_ARRAY);
+ Parcelable[] array = (Parcelable[]) value;
+ for (Parcelable parcelable : array) {
+ if (!(parcelable instanceof Bundle)) {
+ throw new IllegalArgumentException("bundle-array can only hold Bundles");
+ }
+ serializer.startTag(null, TAG_ENTRY);
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BUNDLE);
+ writeBundle((Bundle) parcelable, serializer);
+ serializer.endTag(null, TAG_ENTRY);
+ }
+ } else {
+ serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING_ARRAY);
+ String[] values = (String[]) value;
+ serializer.attribute(null, ATTR_MULTIPLE, Integer.toString(values.length));
+ for (String choice : values) {
+ serializer.startTag(null, TAG_VALUE);
+ serializer.text(choice != null ? choice : "");
+ serializer.endTag(null, TAG_VALUE);
+ }
+ }
+ serializer.endTag(null, TAG_ENTRY);
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index be6550c..958caea 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1398,6 +1398,14 @@
public void onDebug() {
// no-op
}
+ @Override
+ public void onDown() {
+ mOrientationListener.onTouchStart();
+ }
+ @Override
+ public void onUpOrCancel() {
+ mOrientationListener.onTouchEnd();
+ }
});
mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext);
mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
@@ -3501,8 +3509,14 @@
/** {@inheritDoc} */
@Override
public int getSystemDecorLayerLw() {
- if (mStatusBar != null) return mStatusBar.getSurfaceLayer();
- if (mNavigationBar != null) return mNavigationBar.getSurfaceLayer();
+ if (mStatusBar != null && mStatusBar.isVisibleLw()) {
+ return mStatusBar.getSurfaceLayer();
+ }
+
+ if (mNavigationBar != null && mNavigationBar.isVisibleLw()) {
+ return mNavigationBar.getSurfaceLayer();
+ }
+
return 0;
}
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index cfa631f..627b328 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -75,6 +75,7 @@
mDebugFireable = true;
mDownPointers = 0;
captureDown(event, 0);
+ mCallbacks.onDown();
break;
case MotionEvent.ACTION_POINTER_DOWN:
captureDown(event, event.getActionIndex());
@@ -106,6 +107,7 @@
case MotionEvent.ACTION_CANCEL:
mSwipeFireable = false;
mDebugFireable = false;
+ mCallbacks.onUpOrCancel();
break;
default:
if (DEBUG) Slog.d(TAG, "Ignoring " + event);
@@ -192,6 +194,8 @@
void onSwipeFromTop();
void onSwipeFromBottom();
void onSwipeFromRight();
+ void onDown();
+ void onUpOrCancel();
void onDebug();
}
}
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index 0118127..c8fd82e 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -22,6 +22,7 @@
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
@@ -133,6 +134,24 @@
}
}
+ public void onTouchStart() {
+ synchronized (mLock) {
+ if (mSensorEventListener != null) {
+ mSensorEventListener.onTouchStartLocked();
+ }
+ }
+ }
+
+ public void onTouchEnd() {
+ long whenElapsedNanos = SystemClock.elapsedRealtimeNanos();
+
+ synchronized (mLock) {
+ if (mSensorEventListener != null) {
+ mSensorEventListener.onTouchEndLocked(whenElapsedNanos);
+ }
+ }
+ }
+
/**
* Sets the current rotation.
*
@@ -269,6 +288,11 @@
private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS =
500 * NANOS_PER_MS;
+ // The minimum amount of time that must have elapsed since the screen was last touched
+ // before the proposed rotation can change.
+ private static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS =
+ 500 * NANOS_PER_MS;
+
// If the tilt angle remains greater than the specified angle for a minimum of
// the specified time, then the device is deemed to be lying flat
// (just chillin' on a table).
@@ -398,6 +422,10 @@
private long mAccelerationTimestampNanos;
private boolean mAccelerating;
+ // Timestamp when the last touch to the touch screen ended
+ private long mTouchEndedTimestampNanos = Long.MIN_VALUE;
+ private boolean mTouched;
+
// Whether we are locked into an overhead usage mode.
private boolean mOverhead;
@@ -422,6 +450,7 @@
pw.println(prefix + "mSwinging=" + mSwinging);
pw.println(prefix + "mAccelerating=" + mAccelerating);
pw.println(prefix + "mOverhead=" + mOverhead);
+ pw.println(prefix + "mTouched=" + mTouched);
}
@Override
@@ -601,6 +630,7 @@
+ ", isFlat=" + isFlat
+ ", isSwinging=" + isSwinging
+ ", isOverhead=" + mOverhead
+ + ", isTouched=" + mTouched
+ ", timeUntilSettledMS=" + remainingMS(now,
mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS)
+ ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now,
@@ -608,7 +638,9 @@
+ ", timeUntilFlatDelayExpiredMS=" + remainingMS(now,
mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS)
+ ", timeUntilSwingDelayExpiredMS=" + remainingMS(now,
- mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS));
+ mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS)
+ + ", timeUntilTouchDelayExpiredMS=" + remainingMS(now,
+ mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS));
}
}
@@ -710,6 +742,12 @@
return false;
}
+ // The last touch must have ended sufficiently long ago.
+ if (mTouched || now < mTouchEndedTimestampNanos
+ + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS) {
+ return false;
+ }
+
// Looks good!
return true;
}
@@ -796,5 +834,14 @@
private float remainingMS(long now, long until) {
return now >= until ? 0 : (until - now) * 0.000001f;
}
+
+ private void onTouchStartLocked() {
+ mTouched = true;
+ }
+
+ private void onTouchEndLocked(long whenElapsedNanos) {
+ mTouched = false;
+ mTouchEndedTimestampNanos = whenElapsedNanos;
+ }
}
}
diff --git a/services/core/java/com/android/server/updates/TZInfoInstallReceiver.java b/services/core/java/com/android/server/updates/TZInfoInstallReceiver.java
deleted file mode 100644
index 2fe68f8..0000000
--- a/services/core/java/com/android/server/updates/TZInfoInstallReceiver.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.updates;
-
-import android.util.Base64;
-
-import java.io.IOException;
-
-public class TZInfoInstallReceiver extends ConfigUpdateInstallReceiver {
-
- public TZInfoInstallReceiver() {
- super("/data/misc/zoneinfo/", "tzdata", "metadata/", "version");
- }
-
- @Override
- protected void install(byte[] encodedContent, int version) throws IOException {
- super.install(Base64.decode(encodedContent, Base64.DEFAULT), version);
- }
-}
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
new file mode 100644
index 0000000..b260e4e
--- /dev/null
+++ b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
@@ -0,0 +1,54 @@
+/*
+ * 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.server.updates;
+
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import libcore.tzdata.update.TzDataBundleInstaller;
+
+/**
+ * An install receiver responsible for installing timezone data updates.
+ */
+public class TzDataInstallReceiver extends ConfigUpdateInstallReceiver {
+
+ private static final String TAG = "TZDataInstallReceiver";
+
+ private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo");
+ private static final String UPDATE_DIR_NAME = TZ_DATA_DIR.getPath() + "/updates/";
+ private static final String UPDATE_METADATA_DIR_NAME = "metadata/";
+ private static final String UPDATE_VERSION_FILE_NAME = "version";
+ private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_bundle.zip";
+
+ private final TzDataBundleInstaller installer;
+
+ public TzDataInstallReceiver() {
+ super(UPDATE_DIR_NAME, UPDATE_CONTENT_FILE_NAME, UPDATE_METADATA_DIR_NAME,
+ UPDATE_VERSION_FILE_NAME);
+ installer = new TzDataBundleInstaller(TAG, TZ_DATA_DIR);
+ }
+
+ @Override
+ protected void install(byte[] content, int version) throws IOException {
+ boolean valid = installer.install(content);
+ Slog.i(TAG, "Timezone data install valid for this device: " + valid);
+ // Even if !valid, we call super.install(). Only in the event of an exception should we
+ // not. If we didn't do this we could attempt to install repeatedly.
+ super.install(content, version);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index a58f30d..55ec9fc 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -242,7 +242,7 @@
}
// This must be called while inside a transaction.
- boolean stepAnimationLocked(long currentTime) {
+ boolean stepAnimationLocked(long currentTime, final int displayId) {
if (mService.okToDisplay()) {
// We will run animations as long as the display isn't frozen.
@@ -292,7 +292,7 @@
}
mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
- "AppWindowToken");
+ "AppWindowToken", displayId);
clearAnimation();
animating = false;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 46fa38a..897b865 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -159,13 +159,13 @@
final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
final boolean wasAnimating = appAnimator.animation != null
&& appAnimator.animation != AppWindowAnimator.sDummyAnimation;
- if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+ if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
mAnimating = mAppWindowAnimating = true;
} else if (wasAnimating) {
// stopped animating, do one more pass through the layout
setAppLayoutChanges(appAnimator,
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
- "appToken " + appAnimator.mAppToken + " done");
+ "appToken " + appAnimator.mAppToken + " done", displayId);
if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
"updateWindowsApps...: done animating " + appAnimator.mAppToken);
}
@@ -178,12 +178,12 @@
final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
final boolean wasAnimating = appAnimator.animation != null
&& appAnimator.animation != AppWindowAnimator.sDummyAnimation;
- if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+ if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
mAnimating = mAppWindowAnimating = true;
} else if (wasAnimating) {
// stopped animating, do one more pass through the layout
setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
- "exiting appToken " + appAnimator.mAppToken + " done");
+ "exiting appToken " + appAnimator.mAppToken + " done", displayId);
if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
"updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
}
@@ -575,11 +575,11 @@
// This will set mOrientationChangeComplete and cause a pass through layout.
setAppLayoutChanges(appAnimator,
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
- "testTokenMayBeDrawnLocked: freezingScreen");
+ "testTokenMayBeDrawnLocked: freezingScreen", displayId);
} else {
setAppLayoutChanges(appAnimator,
WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
- "testTokenMayBeDrawnLocked");
+ "testTokenMayBeDrawnLocked", displayId);
// We can now show all of the drawn windows!
if (!mService.mOpeningApps.contains(wtoken)) {
@@ -792,28 +792,30 @@
if (displayId < 0) {
return 0;
}
- return mService.getDisplayContentLocked(displayId).pendingLayoutChanges;
+ final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+ return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
}
void setPendingLayoutChanges(final int displayId, final int changes) {
- if (displayId >= 0) {
- mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
+ if (displayId < 0) {
+ return;
+ }
+ final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+ if (displayContent != null) {
+ displayContent.pendingLayoutChanges |= changes;
}
}
- void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
- // Used to track which displays layout changes have been done.
- SparseIntArray displays = new SparseIntArray(2);
+ void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String reason,
+ final int displayId) {
WindowList windows = appAnimator.mAppToken.allAppWindows;
for (int i = windows.size() - 1; i >= 0; i--) {
- final int displayId = windows.get(i).getDisplayId();
- if (displayId >= 0 && displays.indexOfKey(displayId) < 0) {
+ if (displayId == windows.get(i).getDisplayId()) {
setPendingLayoutChanges(displayId, changes);
if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
- mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId));
+ mService.debugLayoutRepeats(reason, getPendingLayoutChanges(displayId));
}
- // Keep from processing this display again.
- displays.put(displayId, changes);
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 32bb78e..6df3bf4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4610,19 +4610,24 @@
" hidden=" + wtoken.hidden + " hiddenRequested=" +
wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
+ mOpeningApps.remove(wtoken);
+ mClosingApps.remove(wtoken);
+ wtoken.waitingToShow = wtoken.waitingToHide = false;
+ wtoken.hiddenRequested = !visible;
+
+ mOpeningApps.remove(wtoken);
+ mClosingApps.remove(wtoken);
+ wtoken.waitingToShow = wtoken.waitingToHide = false;
+ wtoken.hiddenRequested = !visible;
+
// If we are preparing an app transition, then delay changing
// the visibility of this token until we execute that transition.
if (okToDisplay() && mAppTransition.isTransitionSet()) {
- wtoken.hiddenRequested = !visible;
-
if (!wtoken.startingDisplayed) {
if (DEBUG_APP_TRANSITIONS) Slog.v(
TAG, "Setting dummy animation on: " + wtoken);
wtoken.mAppAnimator.setDummyAnimation();
}
- mOpeningApps.remove(wtoken);
- mClosingApps.remove(wtoken);
- wtoken.waitingToShow = wtoken.waitingToHide = false;
wtoken.inPendingTransaction = true;
if (visible) {
mOpeningApps.add(wtoken);
@@ -9059,39 +9064,41 @@
goodToGo = false;
}
}
- if (goodToGo && isWallpaperVisible(mWallpaperTarget)) {
- boolean wallpaperGoodToGo = true;
- for (int curTokenIndex = mWallpaperTokens.size() - 1;
- curTokenIndex >= 0 && wallpaperGoodToGo; curTokenIndex--) {
- WindowToken token = mWallpaperTokens.get(curTokenIndex);
- for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
- curWallpaperIndex--) {
- WindowState wallpaper = token.windows.get(curWallpaperIndex);
- if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
- // We've told this wallpaper to be visible, but it is not drawn yet
- wallpaperGoodToGo = false;
- if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
- // wait for this wallpaper until it is drawn or timeout
- goodToGo = false;
- }
- if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
- mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
- mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
- mH.sendEmptyMessageDelayed(H.WALLPAPER_DRAW_PENDING_TIMEOUT,
- WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
- }
- if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
- "Wallpaper should be visible but has not been drawn yet. " +
- "mWallpaperDrawState=" + mWallpaperDrawState);
- break;
- }
- }
- }
- if (wallpaperGoodToGo) {
- mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
- mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
- }
- }
+// Stuck in a state with mWallpaperDrawState == WALLPAPER_DRAW_PENDING without a timeout. Leave
+// commented out until that is understood.
+// if (goodToGo && isWallpaperVisible(mWallpaperTarget)) {
+// boolean wallpaperGoodToGo = true;
+// for (int curTokenIndex = mWallpaperTokens.size() - 1;
+// curTokenIndex >= 0 && wallpaperGoodToGo; curTokenIndex--) {
+// WindowToken token = mWallpaperTokens.get(curTokenIndex);
+// for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
+// curWallpaperIndex--) {
+// WindowState wallpaper = token.windows.get(curWallpaperIndex);
+// if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
+// // We've told this wallpaper to be visible, but it is not drawn yet
+// wallpaperGoodToGo = false;
+// if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
+// // wait for this wallpaper until it is drawn or timeout
+// goodToGo = false;
+// }
+// if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
+// mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
+// mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
+// mH.sendEmptyMessageDelayed(H.WALLPAPER_DRAW_PENDING_TIMEOUT,
+// WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
+// }
+// if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
+// "Wallpaper should be visible but has not been drawn yet. " +
+// "mWallpaperDrawState=" + mWallpaperDrawState);
+// break;
+// }
+// }
+// }
+// if (wallpaperGoodToGo) {
+// mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
+// mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
+// }
+// }
}
if (goodToGo) {
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 73b5de1..0c58aef 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -78,6 +78,8 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.ContactsContract.QuickContact;
+import android.provider.ContactsInternal;
import android.provider.Settings;
import android.security.Credentials;
import android.security.IKeyChainAliasCallback;
@@ -146,6 +148,8 @@
private static final String LOG_TAG = "DevicePolicyManagerService";
+ private static final boolean VERBOSE_LOG = false; // DO NOT SUBMIT WITH TRUE
+
private static final String DEVICE_POLICIES_XML = "device_policies.xml";
private static final String LOCK_TASK_COMPONENTS_XML = "lock-task-component";
@@ -5435,6 +5439,59 @@
}
}
+ @Override
+ public void startManagedQuickContact(String actualLookupKey, long actualContactId,
+ Intent originalIntent) {
+ final Intent intent = QuickContact.rebuildManagedQuickContactsIntent(
+ actualLookupKey, actualContactId, originalIntent);
+ final int callingUserId = UserHandle.getCallingUserId();
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final int managedUserId = getManagedUserId(callingUserId);
+ if (managedUserId < 0) {
+ return;
+ }
+ if (getCrossProfileCallerIdDisabledForUser(managedUserId)) {
+ if (VERBOSE_LOG) {
+ Log.v(LOG_TAG,
+ "Cross-profile contacts access disabled for user " + managedUserId);
+ }
+ return;
+ }
+ ContactsInternal.startQuickContactWithErrorToastForUser(
+ mContext, intent, new UserHandle(managedUserId));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * @return the user ID of the managed user that is linked to the current user, if any.
+ * Otherwise -1.
+ */
+ public int getManagedUserId(int callingUserId) {
+ if (VERBOSE_LOG) {
+ Log.v(LOG_TAG, "getManagedUserId: callingUserId=" + callingUserId);
+ }
+
+ for (UserInfo ui : mUserManager.getProfiles(callingUserId)) {
+ if (ui.id == callingUserId || !ui.isManagedProfile()) {
+ continue; // Caller user self, or not a managed profile. Skip.
+ }
+ if (VERBOSE_LOG) {
+ Log.v(LOG_TAG, "Managed user=" + ui.id);
+ }
+ return ui.id;
+ }
+ if (VERBOSE_LOG) {
+ Log.v(LOG_TAG, "Managed user not found.");
+ }
+ return -1;
+ }
+
/**
* Sets which packages may enter lock task mode.
*
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8c653e2..53da75b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -53,6 +53,7 @@
import com.android.server.accounts.AccountManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.server.audio.AudioService;
+import com.android.server.camera.CameraService;
import com.android.server.clipboard.ClipboardService;
import com.android.server.content.ContentService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
@@ -408,6 +409,7 @@
AudioService audioService = null;
MmsServiceBroker mmsService = null;
EntropyMixer entropyMixer = null;
+ CameraService cameraService = null;
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -436,6 +438,9 @@
mContentResolver = context.getContentResolver();
+ Slog.i(TAG, "Camera Service");
+ mSystemServiceManager.startService(CameraService.class);
+
// The AccountManager must come before the ContentService
try {
// TODO: seems like this should be disable-able, but req'd by ContentService
@@ -912,6 +917,11 @@
}
}
+ if (!disableNonCoreServices) {
+ ServiceManager.addService(GraphicsStatsService.GRAPHICS_STATS_SERVICE,
+ new GraphicsStatsService(context));
+ }
+
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
}
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index a232a6e..d41629d 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -611,10 +611,22 @@
/**
* Reads a string of specified length from the buffer.
*/
- private static String readAsciiString(ByteBuffer buf, int byteCount) {
+ private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) {
byte[] bytes = new byte[byteCount];
buf.get(bytes);
- return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
+ int length = bytes.length;
+ if (!nullOk) {
+ // Stop at the first null byte. This is because some DHCP options (e.g., the domain
+ // name) are passed to netd via FrameworkListener, which refuses arguments containing
+ // null bytes. We don't do this by default because vendorInfo is an opaque string which
+ // could in theory contain null bytes.
+ for (length = 0; length < bytes.length; length++) {
+ if (bytes[length] == 0) {
+ break;
+ }
+ }
+ }
+ return new String(bytes, 0, length, StandardCharsets.US_ASCII);
}
/**
@@ -797,7 +809,7 @@
break;
case DHCP_HOST_NAME:
expectedLen = optionLen;
- hostName = readAsciiString(packet, optionLen);
+ hostName = readAsciiString(packet, optionLen, false);
break;
case DHCP_MTU:
expectedLen = 2;
@@ -805,7 +817,7 @@
break;
case DHCP_DOMAIN_NAME:
expectedLen = optionLen;
- domainName = readAsciiString(packet, optionLen);
+ domainName = readAsciiString(packet, optionLen, false);
break;
case DHCP_BROADCAST_ADDRESS:
bcAddr = readIpAddress(packet);
@@ -834,7 +846,7 @@
break;
case DHCP_MESSAGE:
expectedLen = optionLen;
- message = readAsciiString(packet, optionLen);
+ message = readAsciiString(packet, optionLen, false);
break;
case DHCP_MAX_MESSAGE_SIZE:
expectedLen = 2;
@@ -850,7 +862,7 @@
break;
case DHCP_VENDOR_CLASS_ID:
expectedLen = optionLen;
- vendorId = readAsciiString(packet, optionLen);
+ vendorId = readAsciiString(packet, optionLen, true);
break;
case DHCP_CLIENT_IDENTIFIER: { // Client identifier
byte[] id = new byte[optionLen];
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index f25fc62..33979b1 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -10,6 +10,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
services.core \
services.devicepolicy \
+ services.net \
easymocklib \
guava \
mockito-target
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
new file mode 100644
index 0000000..2658937
--- /dev/null
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.dhcp;
+
+import android.net.NetworkUtils;
+import android.system.OsConstants;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.net.Inet4Address;
+import java.nio.ByteBuffer;
+
+import static android.net.dhcp.DhcpPacket.*;
+
+
+public class DhcpPacketTest extends TestCase {
+
+ private static Inet4Address SERVER_ADDR =
+ (Inet4Address) NetworkUtils.numericToInetAddress("192.0.2.1");
+ private static Inet4Address CLIENT_ADDR =
+ (Inet4Address) NetworkUtils.numericToInetAddress("192.0.2.234");
+ private static byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+ class TestDhcpPacket extends DhcpPacket {
+ private byte mType;
+ // TODO: Make this a map of option numbers to bytes instead.
+ private byte[] mDomainBytes, mVendorInfoBytes;
+
+ public TestDhcpPacket(byte type, byte[] domainBytes, byte[] vendorInfoBytes) {
+ super(0xdeadbeef, INADDR_ANY, CLIENT_ADDR, INADDR_ANY, INADDR_ANY, CLIENT_MAC, true);
+ mType = type;
+ mDomainBytes = domainBytes;
+ mVendorInfoBytes = vendorInfoBytes;
+ }
+
+ public ByteBuffer buildPacket(int encap, short unusedDestUdp, short unusedSrcUdp) {
+ ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
+ fillInPacket(encap, CLIENT_ADDR, SERVER_ADDR,
+ DHCP_CLIENT, DHCP_SERVER, result, DHCP_BOOTREPLY, false);
+ return result;
+ }
+
+ public void finishPacket(ByteBuffer buffer) {
+ addTlv(buffer, DHCP_MESSAGE_TYPE, mType);
+ if (mDomainBytes != null) {
+ addTlv(buffer, DHCP_DOMAIN_NAME, mDomainBytes);
+ }
+ if (mVendorInfoBytes != null) {
+ addTlv(buffer, DHCP_VENDOR_CLASS_ID, mVendorInfoBytes);
+ }
+ addTlvEnd(buffer);
+ }
+
+ // Convenience method.
+ public ByteBuffer build() {
+ // ENCAP_BOOTP packets don't contain ports, so just pass in 0.
+ ByteBuffer pkt = buildPacket(ENCAP_BOOTP, (short) 0, (short) 0);
+ pkt.flip();
+ return pkt;
+ }
+ }
+
+ private void assertDomainAndVendorInfoParses(
+ String expectedDomain, byte[] domainBytes,
+ String expectedVendorInfo, byte[] vendorInfoBytes) {
+ ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER,
+ domainBytes, vendorInfoBytes).build();
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+ assertEquals(expectedDomain, offerPacket.mDomainName);
+ assertEquals(expectedVendorInfo, offerPacket.mVendorId);
+ }
+
+ @SmallTest
+ public void testDomainName() throws Exception {
+ byte[] nullByte = new byte[] { 0x00 };
+ byte[] twoNullBytes = new byte[] { 0x00, 0x00 };
+ byte[] nonNullDomain = new byte[] {
+ (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l'
+ };
+ byte[] trailingNullDomain = new byte[] {
+ (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l', 0x00
+ };
+ byte[] embeddedNullsDomain = new byte[] {
+ (byte) 'g', (byte) 'o', (byte) 'o', 0x00, 0x00, (byte) 'g', (byte) 'l'
+ };
+ byte[] metered = "ANDROID_METERED".getBytes("US-ASCII");
+
+ byte[] meteredEmbeddedNull = metered.clone();
+ meteredEmbeddedNull[7] = (char) 0;
+
+ byte[] meteredTrailingNull = metered.clone();
+ meteredTrailingNull[meteredTrailingNull.length - 1] = (char) 0;
+
+ assertDomainAndVendorInfoParses("", nullByte, "\u0000", nullByte);
+ assertDomainAndVendorInfoParses("", twoNullBytes, "\u0000\u0000", twoNullBytes);
+ assertDomainAndVendorInfoParses("goo.gl", nonNullDomain, "ANDROID_METERED", metered);
+ assertDomainAndVendorInfoParses("goo", embeddedNullsDomain,
+ "ANDROID\u0000METERED", meteredEmbeddedNull);
+ assertDomainAndVendorInfoParses("goo.gl", trailingNullDomain,
+ "ANDROID_METERE\u0000", meteredTrailingNull);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
new file mode 100644
index 0000000..eb7eb15
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.server.pm;
+
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.Parcelable;
+import android.test.AndroidTestCase;
+import android.util.AtomicFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+public class UserManagerServiceTest extends AndroidTestCase {
+ private static String[] STRING_ARRAY = new String[] {"<tag", "<![CDATA["};
+ private File restrictionsFile;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ restrictionsFile = new File(mContext.getCacheDir(), "restrictions.xml");
+ restrictionsFile.delete();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ restrictionsFile.delete();
+ super.tearDown();
+ }
+
+ public void testWriteReadApplicationRestrictions() throws IOException {
+ AtomicFile atomicFile = new AtomicFile(restrictionsFile);
+ Bundle bundle = createBundle();
+ UserManagerService.writeApplicationRestrictionsLocked(bundle, atomicFile);
+ assertTrue(atomicFile.getBaseFile().exists());
+ String s = FileUtils.readTextFile(restrictionsFile, 10000, "");
+ System.out.println("restrictionsFile: " + s);
+ bundle = UserManagerService.readApplicationRestrictionsLocked(atomicFile);
+ System.out.println("readApplicationRestrictionsLocked bundle: " + bundle);
+ assertBundle(bundle);
+ }
+
+ private Bundle createBundle() {
+ Bundle result = new Bundle();
+ // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
+ result.putBoolean("boolean_0", false);
+ result.putBoolean("boolean_1", true);
+ result.putInt("integer", 100);
+ result.putString("empty", "");
+ result.putString("string", "text");
+ result.putStringArray("string[]", STRING_ARRAY);
+
+ Bundle bundle = new Bundle();
+ bundle.putString("bundle_string", "bundle_string");
+ bundle.putInt("bundle_int", 1);
+ result.putBundle("bundle", bundle);
+
+ Bundle[] bundleArray = new Bundle[2];
+ bundleArray[0] = new Bundle();
+ bundleArray[0].putString("bundle_array_string", "bundle_array_string");
+ bundleArray[0].putBundle("bundle_array_bundle", bundle);
+ bundleArray[1] = new Bundle();
+ bundleArray[1].putString("bundle_array_string2", "bundle_array_string2");
+ result.putParcelableArray("bundle_array", bundleArray);
+ return result;
+ }
+
+ private void assertBundle(Bundle bundle) {
+ assertFalse(bundle.getBoolean("boolean_0"));
+ assertTrue(bundle.getBoolean("boolean_1"));
+ assertEquals(100, bundle.getInt("integer"));
+ assertEquals("", bundle.getString("empty"));
+ assertEquals("text", bundle.getString("string"));
+ assertEquals(Arrays.asList(STRING_ARRAY), Arrays.asList(bundle.getStringArray("string[]")));
+ Parcelable[] bundle_array = bundle.getParcelableArray("bundle_array");
+ assertEquals(2, bundle_array.length);
+ Bundle bundle1 = (Bundle) bundle_array[0];
+ assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
+ assertNotNull(bundle1.getBundle("bundle_array_bundle"));
+ Bundle bundle2 = (Bundle) bundle_array[1];
+ assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
+ Bundle childBundle = bundle.getBundle("bundle");
+ assertEquals("bundle_string", childBundle.getString("bundle_string"));
+ assertEquals(1, childBundle.getInt("bundle_int"));
+ }
+
+}
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 7c101a40f..6ece888 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -29,6 +29,9 @@
import android.system.StructPollfd;
import android.util.Log;
+import com.android.internal.midi.MidiEventScheduler;
+import com.android.internal.midi.MidiEventScheduler.MidiEvent;
+
import libcore.io.IoUtils;
import java.io.Closeable;
@@ -42,7 +45,7 @@
private MidiDeviceServer mServer;
- private final MidiReceiver[] mInputPortReceivers;
+ private final MidiEventScheduler mEventScheduler;
private static final int BUFFER_SIZE = 512;
@@ -99,19 +102,7 @@
for (int i = 0; i < outputCount; i++) {
mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]);
}
-
- mInputPortReceivers = new MidiReceiver[inputCount];
- for (int port = 0; port < inputCount; port++) {
- final int portF = port;
- mInputPortReceivers[port] = new MidiReceiver() {
- @Override
- public void onReceive(byte[] data, int offset, int count, long timestamp)
- throws IOException {
- // FIXME - timestamps are ignored, future posting not supported yet.
- mOutputStreams[portF].write(data, offset, count);
- }
- };
- }
+ mEventScheduler = new MidiEventScheduler(inputCount);
}
private boolean register(Context context, Bundle properties) {
@@ -121,16 +112,22 @@
return false;
}
+ int inputCount = mInputStreams.length;
int outputCount = mOutputStreams.length;
- mServer = midiManager.createDeviceServer(mInputPortReceivers, outputCount,
+ MidiReceiver[] inputPortReceivers = new MidiReceiver[inputCount];
+ for (int port = 0; port < inputCount; port++) {
+ inputPortReceivers[port] = mEventScheduler.getReceiver(port);
+ }
+
+ mServer = midiManager.createDeviceServer(inputPortReceivers, outputCount,
null, null, properties, MidiDeviceInfo.TYPE_USB, null);
if (mServer == null) {
return false;
}
final MidiReceiver[] outputReceivers = mServer.getOutputPortReceivers();
- // FIXME can we only run this when we have a dispatcher that has listeners?
- new Thread() {
+ // Create input thread
+ new Thread("UsbMidiDevice input thread") {
@Override
public void run() {
byte[] buffer = new byte[BUFFER_SIZE];
@@ -160,6 +157,33 @@
} catch (ErrnoException e) {
Log.d(TAG, "reader thread exiting");
}
+ Log.d(TAG, "input thread exit");
+ }
+ }.start();
+
+ // Create output thread
+ new Thread("UsbMidiDevice output thread") {
+ @Override
+ public void run() {
+ while (true) {
+ MidiEvent event;
+ try {
+ event = (MidiEvent)mEventScheduler.waitNextEvent();
+ } catch (InterruptedException e) {
+ // try again
+ continue;
+ }
+ if (event == null) {
+ break;
+ }
+ try {
+ mOutputStreams[event.portNumber].write(event.data, 0, event.count);
+ } catch (IOException e) {
+ Log.e(TAG, "write failed for port " + event.portNumber);
+ }
+ mEventScheduler.addEventToPool(event);
+ }
+ Log.d(TAG, "output thread exit");
}
}.start();
@@ -168,6 +192,8 @@
@Override
public void close() throws IOException {
+ mEventScheduler.close();
+
if (mServer != null) {
mServer.close();
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fbc70db..6bc6de63 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3316,11 +3316,11 @@
* @return the preferred network type, defined in RILConstants.java.
* @hide
*/
- public int getPreferredNetworkType() {
+ public int getPreferredNetworkType(int subId) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.getPreferredNetworkType();
+ return telephony.getPreferredNetworkType(subId);
} catch (RemoteException ex) {
Rlog.e(TAG, "getPreferredNetworkType RemoteException", ex);
} catch (NullPointerException ex) {
@@ -3330,6 +3330,27 @@
}
/**
+ * Sets the network selection mode to automatic.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @hide
+ */
+ public void setNetworkSelectionModeAutomatic(int subId) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ telephony.setNetworkSelectionModeAutomatic(subId);
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setNetworkSelectionModeAutomatic RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "setNetworkSelectionModeAutomatic NPE", ex);
+ }
+ }
+
+ /**
* Set the preferred network type.
* Used for device configuration by some CDMA operators.
* <p>
@@ -3337,15 +3358,16 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
* Or the calling app has carrier privileges. @see #hasCarrierPrivileges
*
+ * @param subId the id of the subscription to set the preferred network type for.
* @param networkType the preferred network type, defined in RILConstants.java.
* @return true on success; false on any failure.
* @hide
*/
- public boolean setPreferredNetworkType(int networkType) {
+ public boolean setPreferredNetworkType(int subId, int networkType) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.setPreferredNetworkType(networkType);
+ return telephony.setPreferredNetworkType(subId, networkType);
} catch (RemoteException ex) {
Rlog.e(TAG, "setPreferredNetworkType RemoteException", ex);
} catch (NullPointerException ex) {
@@ -3364,7 +3386,8 @@
* @return true on success; false on any failure.
*/
public boolean setPreferredNetworkTypeToGlobal() {
- return setPreferredNetworkType(RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
+ return setPreferredNetworkType(getDefaultSubscription(),
+ RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
}
/**
@@ -4448,4 +4471,22 @@
return retval;
}
+
+ /**
+ * Resets telephony manager settings back to factory defaults.
+ *
+ * @hide
+ */
+ public void factoryReset(int subId) {
+ if (SubscriptionManager.isUsableSubIdValue(subId)) {
+ // Enable data
+ setDataEnabled(subId, true);
+ // Set network selection mode to automatic
+ setNetworkSelectionModeAutomatic(subId);
+ // Set preferred mobile network type to the best available
+ setPreferredNetworkType(subId, RILConstants.PREFERRED_NETWORK_MODE);
+ // Turn off roaming
+ SubscriptionManager.from(mContext).setDataRoaming(0, subId);
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c18e3b6..a24859b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -653,9 +653,10 @@
* Get the preferred network type.
* Used for device configuration by some CDMA operators.
*
+ * @param subId the id of the subscription to query.
* @return the preferred network type, defined in RILConstants.java.
*/
- int getPreferredNetworkType();
+ int getPreferredNetworkType(int subId);
/**
* Check TETHER_DUN_REQUIRED and TETHER_DUN_APN settings, net.tethering.noprovisioning
@@ -667,13 +668,21 @@
int getTetherApnRequired();
/**
+ * Set the network selection mode to automatic.
+ *
+ * @param subId the id of the subscription to update.
+ */
+ void setNetworkSelectionModeAutomatic(int subId);
+
+ /**
* Set the preferred network type.
* Used for device configuration by some CDMA operators.
*
+ * @param subId the id of the subscription to update.
* @param networkType the preferred network type, defined in RILConstants.java.
* @return true on success; false on any failure.
*/
- boolean setPreferredNetworkType(int networkType);
+ boolean setPreferredNetworkType(int subId, int networkType);
/**
* User enable/disable Mobile Data.
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 67a8c2b..a204376 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -31,6 +31,7 @@
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
+import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
import android.content.pm.ManifestDigest;
import android.content.pm.PackageInfo;
@@ -725,6 +726,38 @@
* @hide
*/
@Override
+ public void verifyIntentFilter(int id, int verificationCode, List<String> outFailedDomains) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int getIntentVerificationStatus(String packageName, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
public VerifierDeviceIdentity getVerifierDeviceIdentity() {
throw new UnsupportedOperationException();
}
diff --git a/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java b/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java
index 24e4b54..c72efc2 100644
--- a/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java
+++ b/tools/layoutlib/bridge/src/android/text/GreedyLineBreaker.java
@@ -166,7 +166,7 @@
if (lineBreaks.breaks.length != mBreaksList.size()) {
lineBreaks.breaks = new int[mBreaksList.size()];
lineBreaks.widths = new float[mWidthsList.size()];
- lineBreaks.flags = new boolean[mFlagsList.size()];
+ lineBreaks.flags = new int[mFlagsList.size()];
}
int i = 0;
@@ -181,7 +181,7 @@
}
i = 0;
for (boolean b : mFlagsList) {
- lineBreaks.flags[i] = b;
+ lineBreaks.flags[i] = b ? TAB_MASK : 0;
i++;
}
diff --git a/tools/layoutlib/bridge/src/android/text/LineBreaker.java b/tools/layoutlib/bridge/src/android/text/LineBreaker.java
index 8be3635..54445a4 100644
--- a/tools/layoutlib/bridge/src/android/text/LineBreaker.java
+++ b/tools/layoutlib/bridge/src/android/text/LineBreaker.java
@@ -26,6 +26,8 @@
// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
public abstract class LineBreaker {
+ protected static final int TAB_MASK = 0x20000000; // keep in sync with StaticLayout
+
protected final @NonNull List<Primitive> mPrimitives;
protected final @NonNull LineWidth mLineWidth;
protected final @NonNull TabStops mTabStops;
diff --git a/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java b/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java
index d5d7798..cd92581 100644
--- a/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java
+++ b/tools/layoutlib/bridge/src/android/text/OptimizingLineBreaker.java
@@ -51,7 +51,7 @@
assert p.type == PrimitiveType.PENALTY;
breakInfo.breaks = new int[]{0};
breakInfo.widths = new float[]{p.width};
- breakInfo.flags = new boolean[]{false};
+ breakInfo.flags = new int[]{0};
return;
}
Node[] opt = new Node[numBreaks];
@@ -129,7 +129,7 @@
breakInfo.breaks[count] = mPrimitives.get(idx).location;
breakInfo.widths[count] = opt[idx].mWidth;
- breakInfo.flags [count] = opt[idx].mHasTabs;
+ breakInfo.flags [count] = opt[idx].mHasTabs ? TAB_MASK : 0;
idx = opt[idx].mPrev;
}
}
@@ -140,7 +140,7 @@
}
int[] breaks = new int[size];
float[] widths = new float[size];
- boolean[] flags = new boolean[size];
+ int[] flags = new int[size];
int toCopy = Math.min(size, lineBreaks.breaks.length);
System.arraycopy(lineBreaks.breaks, 0, breaks, 0, toCopy);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 99a0edc..275c7d1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2629,4 +2629,25 @@
}
return false;
}
+
+ /**
+ * Resets all wifi manager settings back to factory defaults.
+ *
+ * @hide
+ */
+ public void factoryReset() {
+ // Enable wifi
+ setWifiEnabled(true);
+ // Delete all Wifi SSIDs
+ List<WifiConfiguration> networks = getConfiguredNetworks();
+ if (networks != null) {
+ for (WifiConfiguration config : networks) {
+ removeNetwork(config.networkId);
+ }
+ saveConfiguration();
+ }
+
+ // Turn mobile hotspot off
+ setWifiApEnabled(null, false);
+ }
}