diff options
707 files changed, 12306 insertions, 5013 deletions
diff --git a/Android.mk b/Android.mk index f1e16b841585..9029f4ef1f53 100644 --- a/Android.mk +++ b/Android.mk @@ -483,6 +483,7 @@ aidl_files := \ frameworks/base/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl \ frameworks/base/wifi/java/android/net/wifi/WpsInfo.aidl \ frameworks/base/wifi/java/android/net/wifi/ScanResult.aidl \ + frameworks/base/wifi/java/android/net/wifi/ScanInfo.aidl \ frameworks/base/wifi/java/android/net/wifi/WifiEnterpriseConfig.aidl \ frameworks/base/wifi/java/android/net/wifi/WifiConfiguration.aidl \ frameworks/base/wifi/java/android/net/wifi/WifiInfo.aidl \ diff --git a/api/current.txt b/api/current.txt index c6f349f53ea8..e3c93663e189 100644 --- a/api/current.txt +++ b/api/current.txt @@ -414,6 +414,7 @@ package android { field public static final int contentInsetRight = 16843862; // 0x1010456 field public static final int contentInsetStart = 16843859; // 0x1010453 field public static final int contextClickable = 16844007; // 0x10104e7 + field public static final int contextPopupMenuStyle = 16844032; // 0x1010500 field public static final int controlX1 = 16843772; // 0x10103fc field public static final int controlX2 = 16843774; // 0x10103fe field public static final int controlY1 = 16843773; // 0x10103fd @@ -1220,6 +1221,7 @@ package android { field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f field public static final int textAppearanceMedium = 16842817; // 0x1010041 field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044 + field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501 field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0 field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1 field public static final int textAppearanceSmall = 16842818; // 0x1010042 @@ -4014,6 +4016,23 @@ package android.app { field public java.lang.String serviceDetails; } + public class AutomaticZenRule implements android.os.Parcelable { + ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean); + ctor public AutomaticZenRule(android.os.Parcel); + method public int describeContents(); + method public android.net.Uri getConditionId(); + method public int getInterruptionFilter(); + method public java.lang.String getName(); + method public android.content.ComponentName getOwner(); + method public boolean isEnabled(); + method public void setConditionId(android.net.Uri); + method public void setEnabled(boolean); + method public void setInterruptionFilter(int); + method public void setName(java.lang.String); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR; + } + public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener { ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int); ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int); @@ -5059,15 +5078,20 @@ package android.app { } public class NotificationManager { + method public boolean addOrUpdateAutomaticZenRule(android.app.AutomaticZenRule); method public void cancel(int); method public void cancel(java.lang.String, int); method public void cancelAll(); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); + method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String); + method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules(); method public final int getCurrentInterruptionFilter(); method public android.app.NotificationManager.Policy getNotificationPolicy(); method public boolean isNotificationPolicyAccessGranted(); method public void notify(int, android.app.Notification); method public void notify(java.lang.String, int, android.app.Notification); + method public boolean removeAutomaticZenRule(java.lang.String); + method public boolean renameAutomaticZenRule(java.lang.String, java.lang.String); method public final void setInterruptionFilter(int); method public void setNotificationPolicy(android.app.NotificationManager.Policy); field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED"; @@ -18131,6 +18155,7 @@ package android.mtp { method public boolean importFile(int, java.lang.String); method public boolean importFile(int, android.os.ParcelFileDescriptor); method public boolean open(android.hardware.usb.UsbDeviceConnection); + method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal); method public boolean sendObject(int, int, android.os.ParcelFileDescriptor); method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo); } @@ -18142,6 +18167,11 @@ package android.mtp { method public final java.lang.String getVersion(); } + public class MtpEvent { + ctor public MtpEvent(); + method public int getEventCode(); + } + public final class MtpObjectInfo { method public final int getAssociationDesc(); method public final int getAssociationType(); @@ -18251,6 +18281,7 @@ package android.net { field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1 field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; + field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo"; field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover"; field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK"; @@ -19157,6 +19188,22 @@ package android.net.sip { package android.net.wifi { + public class ScanInfo implements android.os.Parcelable { + ctor public ScanInfo(android.net.wifi.ScanResult); + ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int); + method public int describeContents(); + method public long getBssid(); + method public byte[] getIconData(); + method public java.lang.String getIconType(); + method public java.lang.String getName(); + method public int getOsuIdentity(); + method public int getRssi(); + method public android.net.wifi.ScanResult getScanResult(); + method public java.lang.String getServiceDescription(); + method public java.lang.String getSsid(); + method public void writeToParcel(android.os.Parcel, int); + } + public class ScanResult implements android.os.Parcelable { method public int describeContents(); method public boolean is80211mcResponder(); @@ -19357,6 +19404,7 @@ package android.net.wifi { method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks(); method public android.net.wifi.WifiInfo getConnectionInfo(); method public android.net.DhcpInfo getDhcpInfo(); + method public java.util.List<android.net.wifi.ScanInfo> getScanInfos(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); method public int getWifiState(); method public boolean is5GHzBandSupported(); @@ -19372,6 +19420,7 @@ package android.net.wifi { method public boolean reconnect(); method public boolean removeNetwork(int); method public boolean saveConfiguration(); + method public void setOsuSelection(int); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); method public boolean setWifiEnabled(boolean); @@ -23540,7 +23589,7 @@ package android.os { method public static final int myPid(); method public static final int myTid(); method public static final int myUid(); - method public static final android.os.UserHandle myUserHandle(); + method public static android.os.UserHandle myUserHandle(); method public static final void sendSignal(int, int); method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException; method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException; @@ -36522,6 +36571,7 @@ package android.view { method public void setY(float); method public void setZ(float); method public boolean showContextMenu(); + method public boolean showContextMenu(float, float); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int); method public void startAnimation(android.view.animation.Animation); @@ -36988,6 +37038,7 @@ package android.view { method public void setTransitionGroup(boolean); method public boolean shouldDelayChildPressedState(); method public boolean showContextMenuForChild(android.view.View); + method public boolean showContextMenuForChild(android.view.View, float, float); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); method public void startLayoutAnimation(); @@ -37109,6 +37160,7 @@ package android.view { method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public abstract void requestTransparentRegion(android.view.View); method public abstract boolean showContextMenuForChild(android.view.View); + method public abstract boolean showContextMenuForChild(android.view.View, float, float); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); } @@ -40887,6 +40939,7 @@ package android.widget { method public int getInputMethodMode(); method public int getMaxAvailableHeight(android.view.View); method public int getMaxAvailableHeight(android.view.View, int); + method public int getMaxAvailableHeight(android.view.View, int, boolean); method public boolean getOverlapAnchor(); method public int getSoftInputMode(); method public int getWidth(); @@ -45330,7 +45383,10 @@ package java.lang.reflect { } public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { + method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); + method public java.lang.annotation.Annotation[] getAnnotations(); + method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<T> getDeclaringClass(); method public java.lang.Class<?>[] getExceptionTypes(); method public java.lang.reflect.Type[] getGenericExceptionTypes(); @@ -45340,6 +45396,7 @@ package java.lang.reflect { method public java.lang.annotation.Annotation[][] getParameterAnnotations(); method public java.lang.Class<?>[] getParameterTypes(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters(); + method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isSynthetic(); method public boolean isVarArgs(); method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException; @@ -45413,7 +45470,10 @@ package java.lang.reflect { } public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { + method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); + method public java.lang.annotation.Annotation[] getAnnotations(); + method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<?> getDeclaringClass(); method public java.lang.Object getDefaultValue(); method public java.lang.Class<?>[] getExceptionTypes(); @@ -45427,6 +45487,7 @@ package java.lang.reflect { method public java.lang.Class<?> getReturnType(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters(); method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException; + method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isBridge(); method public boolean isSynthetic(); method public boolean isVarArgs(); diff --git a/api/system-current.txt b/api/system-current.txt index c7e82cd99f07..b1590d85c766 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -506,6 +506,7 @@ package android { field public static final int contentInsetRight = 16843862; // 0x1010456 field public static final int contentInsetStart = 16843859; // 0x1010453 field public static final int contextClickable = 16844007; // 0x10104e7 + field public static final int contextPopupMenuStyle = 16844032; // 0x1010500 field public static final int controlX1 = 16843772; // 0x10103fc field public static final int controlX2 = 16843774; // 0x10103fe field public static final int controlY1 = 16843773; // 0x10103fd @@ -1316,6 +1317,7 @@ package android { field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f field public static final int textAppearanceMedium = 16842817; // 0x1010041 field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044 + field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501 field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0 field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1 field public static final int textAppearanceSmall = 16842818; // 0x1010042 @@ -4125,6 +4127,23 @@ package android.app { field public java.lang.String serviceDetails; } + public class AutomaticZenRule implements android.os.Parcelable { + ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean); + ctor public AutomaticZenRule(android.os.Parcel); + method public int describeContents(); + method public android.net.Uri getConditionId(); + method public int getInterruptionFilter(); + method public java.lang.String getName(); + method public android.content.ComponentName getOwner(); + method public boolean isEnabled(); + method public void setConditionId(android.net.Uri); + method public void setEnabled(boolean); + method public void setInterruptionFilter(int); + method public void setName(java.lang.String); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR; + } + public class BroadcastOptions { method public static android.app.BroadcastOptions makeBasic(); method public void setTemporaryAppWhitelistDuration(long); @@ -5176,15 +5195,20 @@ package android.app { } public class NotificationManager { + method public boolean addOrUpdateAutomaticZenRule(android.app.AutomaticZenRule); method public void cancel(int); method public void cancel(java.lang.String, int); method public void cancelAll(); method public android.service.notification.StatusBarNotification[] getActiveNotifications(); + method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String); + method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules(); method public final int getCurrentInterruptionFilter(); method public android.app.NotificationManager.Policy getNotificationPolicy(); method public boolean isNotificationPolicyAccessGranted(); method public void notify(int, android.app.Notification); method public void notify(java.lang.String, int, android.app.Notification); + method public boolean removeAutomaticZenRule(java.lang.String); + method public boolean renameAutomaticZenRule(java.lang.String, java.lang.String); method public final void setInterruptionFilter(int); method public void setNotificationPolicy(android.app.NotificationManager.Policy); field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED"; @@ -19643,6 +19667,7 @@ package android.mtp { method public boolean importFile(int, java.lang.String); method public boolean importFile(int, android.os.ParcelFileDescriptor); method public boolean open(android.hardware.usb.UsbDeviceConnection); + method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal); method public boolean sendObject(int, int, android.os.ParcelFileDescriptor); method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo); } @@ -19654,6 +19679,11 @@ package android.mtp { method public final java.lang.String getVersion(); } + public class MtpEvent { + ctor public MtpEvent(); + method public int getEventCode(); + } + public final class MtpObjectInfo { method public final int getAssociationDesc(); method public final int getAssociationType(); @@ -19763,6 +19793,7 @@ package android.net { field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1 field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; + field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo"; field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover"; field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK"; @@ -20910,6 +20941,22 @@ package android.net.wifi { field public byte id; } + public class ScanInfo implements android.os.Parcelable { + ctor public ScanInfo(android.net.wifi.ScanResult); + ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int); + method public int describeContents(); + method public long getBssid(); + method public byte[] getIconData(); + method public java.lang.String getIconType(); + method public java.lang.String getName(); + method public int getOsuIdentity(); + method public int getRssi(); + method public android.net.wifi.ScanResult getScanResult(); + method public java.lang.String getServiceDescription(); + method public java.lang.String getSsid(); + method public void writeToParcel(android.os.Parcel, int); + } + public class ScanResult implements android.os.Parcelable { method public int describeContents(); method public boolean is80211mcResponder(); @@ -21135,6 +21182,7 @@ package android.net.wifi { method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics(); method public android.net.DhcpInfo getDhcpInfo(); method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks(); + method public java.util.List<android.net.wifi.ScanInfo> getScanInfos(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); method public int getWifiState(); method public boolean is5GHzBandSupported(); @@ -21154,6 +21202,7 @@ package android.net.wifi { method public boolean reconnect(); method public boolean removeNetwork(int); method public boolean saveConfiguration(); + method public void setOsuSelection(int); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); method public boolean setWifiEnabled(boolean); @@ -25492,7 +25541,7 @@ package android.os { method public static final int myPid(); method public static final int myTid(); method public static final int myUid(); - method public static final android.os.UserHandle myUserHandle(); + method public static android.os.UserHandle myUserHandle(); method public static final void sendSignal(int, int); method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException; method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException; @@ -25668,8 +25717,8 @@ package android.os { ctor public UserHandle(android.os.Parcel); method public int describeContents(); method public int getIdentifier(); - method public final boolean isOwner(); - method public static final int myUserId(); + method public boolean isOwner(); + method public static int myUserId(); method public static android.os.UserHandle readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); method public static void writeToParcel(android.os.UserHandle, android.os.Parcel); @@ -32843,6 +32892,7 @@ package android.telecom { field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED"; field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL"; field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED"; + field public static final java.lang.String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED"; field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS"; field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS"; field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION"; @@ -38816,6 +38866,7 @@ package android.view { method public void setY(float); method public void setZ(float); method public boolean showContextMenu(); + method public boolean showContextMenu(float, float); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int); method public void startAnimation(android.view.animation.Animation); @@ -39282,6 +39333,7 @@ package android.view { method public void setTransitionGroup(boolean); method public boolean shouldDelayChildPressedState(); method public boolean showContextMenuForChild(android.view.View); + method public boolean showContextMenuForChild(android.view.View, float, float); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); method public void startLayoutAnimation(); @@ -39403,6 +39455,7 @@ package android.view { method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public abstract void requestTransparentRegion(android.view.View); method public abstract boolean showContextMenuForChild(android.view.View); + method public abstract boolean showContextMenuForChild(android.view.View, float, float); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); } @@ -43495,6 +43548,7 @@ package android.widget { method public int getInputMethodMode(); method public int getMaxAvailableHeight(android.view.View); method public int getMaxAvailableHeight(android.view.View, int); + method public int getMaxAvailableHeight(android.view.View, int, boolean); method public boolean getOverlapAnchor(); method public int getSoftInputMode(); method public int getWidth(); @@ -47938,7 +47992,10 @@ package java.lang.reflect { } public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { + method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); + method public java.lang.annotation.Annotation[] getAnnotations(); + method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<T> getDeclaringClass(); method public java.lang.Class<?>[] getExceptionTypes(); method public java.lang.reflect.Type[] getGenericExceptionTypes(); @@ -47948,6 +48005,7 @@ package java.lang.reflect { method public java.lang.annotation.Annotation[][] getParameterAnnotations(); method public java.lang.Class<?>[] getParameterTypes(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters(); + method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isSynthetic(); method public boolean isVarArgs(); method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException; @@ -48021,7 +48079,10 @@ package java.lang.reflect { } public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { + method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); + method public java.lang.annotation.Annotation[] getAnnotations(); + method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<?> getDeclaringClass(); method public java.lang.Object getDefaultValue(); method public java.lang.Class<?>[] getExceptionTypes(); @@ -48035,6 +48096,7 @@ package java.lang.reflect { method public java.lang.Class<?> getReturnType(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters(); method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException; + method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isBridge(); method public boolean isSynthetic(); method public boolean isVarArgs(); diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 20ac8d83ebad..5c9fd51d606d 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -163,6 +163,7 @@ public class Am extends BaseCommand { " am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" + " am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" + " am get-config\n" + + " am suppress-resize-config-changes <true|false>\n" + " am set-inactive [--user <USER_ID>] <PACKAGE> true|false\n" + " am get-inactive [--user <USER_ID>] <PACKAGE>\n" + " am send-trim-memory [--user <USER_ID>] <PROCESS>\n" + @@ -326,6 +327,8 @@ public class Am extends BaseCommand { "\n" + "am get-config: retrieve the configuration and any recent configurations\n" + " of the device.\n" + + "am suppress-resize-config-changes: suppresses configuration changes due to\n" + + " user resizing an activity/task.\n" + "\n" + "am set-inactive: sets the inactive state of an app.\n" + "\n" + @@ -453,6 +456,8 @@ public class Am extends BaseCommand { runTask(); } else if (op.equals("get-config")) { runGetConfig(); + } else if (op.equals("suppress-resize-config-changes")) { + runSuppressResizeConfigChanges(); } else if (op.equals("set-inactive")) { runSetInactive(); } else if (op.equals("get-inactive")) { @@ -2606,6 +2611,16 @@ public class Am extends BaseCommand { } } + private void runSuppressResizeConfigChanges() throws Exception { + boolean suppress = Boolean.valueOf(nextArgRequired()); + + try { + mAm.suppressResizeConfigChanges(suppress); + } catch (RemoteException e) { + System.err.println("Error suppressing resize config changes: " + e); + } + } + private void runSetInactive() throws Exception { int userId = UserHandle.USER_CURRENT; diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 3f0a4445fdce..ebf508514b3c 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -22,11 +22,13 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; +import android.accounts.IAccountManager; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.PackageInstallObserver; import android.content.ComponentName; +import android.content.Context; import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; @@ -92,6 +94,7 @@ public final class Pm { IPackageManager mPm; IPackageInstaller mInstaller; IUserManager mUm; + IAccountManager mAm; private WeakHashMap<String, Resources> mResourceCache = new WeakHashMap<String, Resources>(); @@ -122,9 +125,10 @@ public final class Pm { if (args.length < 1) { return showUsage(); } - - mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user")); + mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE)); + mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE)); mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + if (mPm == null) { System.err.println(PM_NOT_RUNNING_ERR); return 1; @@ -1381,6 +1385,8 @@ public final class Pm { } } else if ("--managed".equals(opt)) { flags |= UserInfo.FLAG_MANAGED_PROFILE; + } else if ("--restricted".equals(opt)) { + flags |= UserInfo.FLAG_RESTRICTED; } else { System.err.println("Error: unknown option " + opt); showUsage(); @@ -1394,12 +1400,18 @@ public final class Pm { } name = arg; try { - UserInfo info = null; - if (userId < 0) { + UserInfo info; + if ((flags & UserInfo.FLAG_RESTRICTED) != 0) { + // In non-split user mode, userId can only be SYSTEM + int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM; + info = mUm.createRestrictedProfile(name, parentUserId); + mAm.addSharedAccountsFromParentUser(userId, parentUserId); + } else if (userId < 0) { info = mUm.createUser(name, flags); } else { info = mUm.createProfileForUser(name, flags, userId); } + if (info != null) { System.out.println("Success: created user id " + info.id); return 1; @@ -2122,7 +2134,7 @@ public final class Pm { System.err.println(" pm get-install-location"); System.err.println(" pm set-permission-enforced PERMISSION [true|false]"); System.err.println(" pm trim-caches DESIRED_FREE_SPACE [internal|UUID]"); - System.err.println(" pm create-user [--profileOf USER_ID] [--managed] USER_NAME"); + System.err.println(" pm create-user [--profileOf USER_ID] [--managed] [--restricted] USER_NAME"); System.err.println(" pm remove-user USER_ID"); System.err.println(" pm get-max-users"); System.err.println(""); diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index d751f96f65f6..0a7568a8c876 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -16,6 +16,7 @@ package android.accounts; +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.Size; import android.app.Activity; @@ -423,6 +424,7 @@ public class AccountManager { * @return An array of {@link Account}, one for each account. Empty * (never null) if no accounts have been added. */ + @NonNull @RequiresPermission(GET_ACCOUNTS) public Account[] getAccounts() { try { @@ -448,6 +450,7 @@ public class AccountManager { * @return An array of {@link Account}, one for each account. Empty * (never null) if no accounts have been added. */ + @NonNull @RequiresPermission(GET_ACCOUNTS) public Account[] getAccountsAsUser(int userId) { try { @@ -466,6 +469,7 @@ public class AccountManager { * @param uid the uid of the calling app. * @return the accounts that are available to this package and user. */ + @NonNull public Account[] getAccountsForPackage(String packageName, int uid) { try { return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName()); @@ -483,6 +487,7 @@ public class AccountManager { * @return An array of {@link Account}, one per matching account. Empty * (never null) if no accounts of the specified type have been added. */ + @NonNull public Account[] getAccountsByTypeForPackage(String type, String packageName) { try { return mService.getAccountsByTypeForPackage(type, packageName, @@ -515,12 +520,14 @@ public class AccountManager { * @return An array of {@link Account}, one per matching account. Empty * (never null) if no accounts of the specified type have been added. */ + @NonNull @RequiresPermission(GET_ACCOUNTS) public Account[] getAccountsByType(String type) { return getAccountsByTypeAsUser(type, Process.myUserHandle()); } /** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */ + @NonNull public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) { try { return mService.getAccountsAsUser(type, userHandle.getIdentifier(), @@ -1537,23 +1544,22 @@ public class AccountManager { }.start(); } + /** - * Adds a shared account from the primary user to a secondary user. Adding the shared account + * Adds shared accounts from a parent user to a secondary user. Adding the shared account * doesn't take effect immediately. When the target user starts up, any pending shared accounts * are attempted to be copied to the target user from the primary via calls to the * authenticator. - * @param account the account to share - * @param user the target user - * @return + * @param parentUser parent user + * @param user target user * @hide */ - public boolean addSharedAccount(final Account account, UserHandle user) { + public void addSharedAccountsFromParentUser(UserHandle parentUser, UserHandle user) { try { - boolean val = mService.addSharedAccountAsUser(account, user.getIdentifier()); - return val; + mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(), + user.getIdentifier()); } catch (RemoteException re) { - // won't ever happen - throw new RuntimeException(re); + throw new IllegalStateException(re); } } diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 4378df408d10..0d95db1d8302 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -74,9 +74,9 @@ interface IAccountManager { String authTokenType); /* Shared accounts */ - boolean addSharedAccountAsUser(in Account account, int userId); Account[] getSharedAccountsAsUser(int userId); boolean removeSharedAccountAsUser(in Account account, int userId); + void addSharedAccountsFromParentUser(int parentUserId, int userId); /* Account renaming. */ void renameAccount(in IAccountManagerResponse response, in Account accountToRename, String newName); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 4997dc751082..f60250cc6eb1 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -3742,6 +3742,12 @@ public class Activity extends ContextThemeWrapper } @Override + public void setTheme(int resid) { + super.setTheme(resid); + mWindow.setTheme(resid); + } + + @Override protected void onApplyThemeResource(Resources.Theme theme, @StyleRes int resid, boolean first) { if (mParent == null) { diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 4191dce79be8..6606f9be2e79 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -478,18 +478,26 @@ public class ActivityManager { /** * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates + * that the resize is from the window manager (instead of the user) due to a screen + * rotation change. + * @hide + */ + public static final int RESIZE_MODE_SYSTEM_SCREEN_ROTATION = 1; + + /** + * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates * that the resize is initiated by the user (most likely via a drag action on the * window's edge or corner). * @hide */ - public static final int RESIZE_MODE_USER = 1; + public static final int RESIZE_MODE_USER = 2; /** * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates * that the resize should be performed even if the bounds appears unchanged. * @hide */ - public static final int RESIZE_MODE_FORCED = 2; + public static final int RESIZE_MODE_FORCED = 3; /** @hide */ public int getFrontActivityScreenCompatMode() { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 3864a4bba1f9..cb1a89fd6601 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2682,6 +2682,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reportSizeConfigurations(token, horizontal, vertical); return true; } + case SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final boolean suppress = data.readInt() == 1; + suppressResizeConfigChanges(suppress); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -6216,5 +6223,17 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + @Override + public void suppressResizeConfigChanges(boolean suppress) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(suppress ? 1 : 0); + mRemote.transact(SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 9c0d93123d77..371c92393d17 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -239,6 +239,8 @@ public class ActivityView extends ViewGroup { } mTextureView.setSurfaceTextureListener(null); + + mThread.quit(); } private void attachToSurfaceWhenReady() { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 5544a7150625..f29dba263a5c 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -126,8 +126,14 @@ public class ApplicationPackageManager extends PackageManager { @Override public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException { + return getPackageInfoAsUser(packageName, flags, mContext.getUserId()); + } + + @Override + public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) + throws NameNotFoundException { try { - PackageInfo pi = mPM.getPackageInfo(packageName, flags, mContext.getUserId()); + PackageInfo pi = mPM.getPackageInfo(packageName, flags, userId); if (pi != null) { return pi; } @@ -1338,7 +1344,7 @@ public class ApplicationPackageManager extends PackageManager { final VerificationParams verificationParams = new VerificationParams(null, null, null, VerificationParams.NO_UID, null); installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags, - installerPackageName, verificationParams, null); + installerPackageName, verificationParams, null, mContext.getUserId()); } @Override @@ -1348,7 +1354,7 @@ public class ApplicationPackageManager extends PackageManager { final VerificationParams verificationParams = new VerificationParams(verificationURI, null, null, VerificationParams.NO_UID, manifestDigest); installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags, - installerPackageName, verificationParams, encryptionParams); + installerPackageName, verificationParams, encryptionParams, mContext.getUserId()); } @Override @@ -1356,15 +1362,23 @@ public class ApplicationPackageManager extends PackageManager { IPackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags, - installerPackageName, verificationParams, encryptionParams); + installerPackageName, verificationParams, encryptionParams, mContext.getUserId()); } @Override public void installPackage(Uri packageURI, PackageInstallObserver observer, int flags, String installerPackageName) { + installPackageAsUser(packageURI, observer, flags, installerPackageName, + mContext.getUserId()); + } + + @Override + public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, int flags, + String installerPackageName, int userId) { final VerificationParams verificationParams = new VerificationParams(null, null, null, VerificationParams.NO_UID, null); - installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null); + installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null, + userId); } @Override @@ -1375,7 +1389,7 @@ public class ApplicationPackageManager extends PackageManager { final VerificationParams verificationParams = new VerificationParams(verificationURI, null, null, VerificationParams.NO_UID, manifestDigest); installCommon(packageURI, observer, flags, installerPackageName, verificationParams, - encryptionParams); + encryptionParams, mContext.getUserId()); } @Override @@ -1383,12 +1397,13 @@ public class ApplicationPackageManager extends PackageManager { PackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { installCommon(packageURI, observer, flags, installerPackageName, verificationParams, - encryptionParams); + encryptionParams, mContext.getUserId()); } private void installCommon(Uri packageURI, PackageInstallObserver observer, int flags, String installerPackageName, - VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { + VerificationParams verificationParams, ContainerEncryptionParams encryptionParams, + int userId) { if (!"file".equals(packageURI.getScheme())) { throw new UnsupportedOperationException("Only file:// URIs are supported"); } @@ -1398,17 +1413,22 @@ public class ApplicationPackageManager extends PackageManager { final String originPath = packageURI.getPath(); try { - mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName, - verificationParams, null); + mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName, + verificationParams, null, userId); } catch (RemoteException ignored) { } } @Override - public int installExistingPackage(String packageName) + public int installExistingPackage(String packageName) throws NameNotFoundException { + return installExistingPackageAsUser(packageName, mContext.getUserId()); + } + + @Override + public int installExistingPackageAsUser(String packageName, int userId) throws NameNotFoundException { try { - int res = mPM.installExistingPackageAsUser(packageName, UserHandle.myUserId()); + int res = mPM.installExistingPackageAsUser(packageName, userId); if (res == INSTALL_FAILED_INVALID_URI) { throw new NameNotFoundException("Package " + packageName + " doesn't exist"); } @@ -1706,8 +1726,14 @@ public class ApplicationPackageManager extends PackageManager { @Override public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) { + deletePackageAsUser(packageName, observer, flags, mContext.getUserId()); + } + + @Override + public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags, + int userId) { try { - mPM.deletePackageAsUser(packageName, observer, UserHandle.myUserId(), flags); + mPM.deletePackageAsUser(packageName, observer, userId, flags); } catch (RemoteException e) { // Should never happen! } @@ -1812,7 +1838,7 @@ public class ApplicationPackageManager extends PackageManager { public void replacePreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) { try { - mPM.replacePreferredActivity(filter, match, set, activity, UserHandle.myUserId()); + mPM.replacePreferredActivity(filter, match, set, activity, mContext.getUserId()); } catch (RemoteException e) { // Should never happen! } @@ -2143,7 +2169,7 @@ public class ApplicationPackageManager extends PackageManager { } private UserInfo getUserIfProfile(int userHandle) { - List<UserInfo> userProfiles = getUserManager().getProfiles(UserHandle.myUserId()); + List<UserInfo> userProfiles = getUserManager().getProfiles(mContext.getUserId()); for (UserInfo user : userProfiles) { if (user.id == userHandle) { return user; diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/core/java/android/app/AutomaticZenRule.aidl index 7dc91d164e2e..feb21d657c6a 100644 --- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml +++ b/core/java/android/app/AutomaticZenRule.aidl @@ -1,6 +1,5 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * Copyright (c) 2012, The Android Open Source Project +/** + * 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. @@ -13,9 +12,8 @@ * 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> - <!-- Recent Applications parameters --> - <dimen name="status_bar_recents_app_label_width">140dip</dimen> -</resources> + */ + +package android.app; + +parcelable AutomaticZenRule;
\ No newline at end of file diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java new file mode 100644 index 000000000000..fea5624411ad --- /dev/null +++ b/core/java/android/app/AutomaticZenRule.java @@ -0,0 +1,190 @@ +/** + * Copyright (c) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import android.content.ComponentName; +import android.net.Uri; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Rule instance information for zen mode. + */ +public class AutomaticZenRule implements Parcelable { + + private boolean enabled = false; + private String name; + private int interruptionFilter; + private Uri conditionId; + private ComponentName owner; + + /** + * Creates an automatic zen rule. + * + * @param name The name of the rule. + * @param owner The Condition Provider service that owns this rule. + * @param conditionId A representation of the state that should cause the Condition Provider + * service to apply the interruption filter. + * @param interruptionFilter The interruption filter defines which notifications are allowed to + * interrupt the user (e.g. via sound & vibration) while this rule + * is active. + * @param enabled Whether the rule is enabled. + */ + public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, + int interruptionFilter, boolean enabled) { + this.name = name; + this.owner = owner; + this.conditionId = conditionId; + this.interruptionFilter = interruptionFilter; + this.enabled = enabled; + } + + public AutomaticZenRule(Parcel source) { + enabled = source.readInt() == 1; + if (source.readInt() == 1) { + name = source.readString(); + } + interruptionFilter = source.readInt(); + conditionId = source.readParcelable(null); + owner = source.readParcelable(null); + } + + /** + * Returns the {@link ComponentName} of the condition provider service that owns this rule. + */ + public ComponentName getOwner() { + return owner; + } + + /** + * Returns the representation of the state that causes this rule to become active. + */ + public Uri getConditionId() { + return conditionId; + } + + /** + * Returns the interruption filter that is applied when this rule is active. + */ + public int getInterruptionFilter() { + return interruptionFilter; + } + + /** + * Returns the name of this rule. + */ + public String getName() { + return name; + } + + /** + * Returns whether this rule is enabled. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Sets the representation of the state that causes this rule to become active. + */ + public void setConditionId(Uri conditionId) { + this.conditionId = conditionId; + } + + /** + * Sets the interruption filter that is applied when this rule is active. + * @param interruptionFilter One of the INTERRUPTION_FILTER_ constants in NotificationManager. + */ + public void setInterruptionFilter(int interruptionFilter) { + this.interruptionFilter = interruptionFilter; + } + + /** + * Sets the name of this rule. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Enables this rule. + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(enabled ? 1 : 0); + if (name != null) { + dest.writeInt(1); + dest.writeString(name); + } else { + dest.writeInt(0); + } + dest.writeInt(interruptionFilter); + dest.writeParcelable(conditionId, 0); + dest.writeParcelable(owner, 0); + } + + @Override + public String toString() { + return new StringBuilder(AutomaticZenRule.class.getSimpleName()).append('[') + .append("enabled=").append(enabled) + .append(",name=").append(name) + .append(",interruptionFilter=").append(interruptionFilter) + .append(",conditionId=").append(conditionId) + .append(",owner=").append(owner) + .append(']').toString(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof AutomaticZenRule)) return false; + if (o == this) return true; + final AutomaticZenRule other = (AutomaticZenRule) o; + return other.enabled == enabled + && Objects.equals(other.name, name) + && other.interruptionFilter == interruptionFilter + && Objects.equals(other.conditionId, conditionId) + && Objects.equals(other.owner, owner); + } + + @Override + public int hashCode() { + return Objects.hash(enabled, name, interruptionFilter, conditionId, owner); + } + + public static final Parcelable.Creator<AutomaticZenRule> CREATOR + = new Parcelable.Creator<AutomaticZenRule>() { + @Override + public AutomaticZenRule createFromParcel(Parcel source) { + return new AutomaticZenRule(source); + } + @Override + public AutomaticZenRule[] newArray(int size) { + return new AutomaticZenRule[size]; + } + }; +}
\ No newline at end of file diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 2180bcc1e4b9..478fdd14e093 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -535,6 +535,8 @@ public interface IActivityManager extends IInterface { public int getActivityStackId(IBinder token) throws RemoteException; public void moveActivityToStack(IBinder token, int stackId) throws RemoteException; + public void suppressResizeConfigChanges(boolean suppress) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -891,4 +893,5 @@ public interface IActivityManager extends IInterface { int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344; int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345; int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346; + int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347; } diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index f78fb47e5f5e..920fbe9cfc1c 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -30,6 +30,7 @@ import android.service.notification.IConditionListener; import android.service.notification.IConditionProvider; import android.service.notification.INotificationListener; import android.service.notification.StatusBarNotification; +import android.app.AutomaticZenRule; import android.service.notification.ZenModeConfig; /** {@hide} */ @@ -92,6 +93,11 @@ interface INotificationManager String[] getPackagesRequestingNotificationPolicyAccess(); boolean isNotificationPolicyAccessGrantedForPackage(String pkg); void setNotificationPolicyAccessGranted(String pkg, boolean granted); + AutomaticZenRule getAutomaticZenRule(String name); + List<AutomaticZenRule> getAutomaticZenRules(); + boolean addOrUpdateAutomaticZenRule(in AutomaticZenRule automaticZenRule); + boolean renameAutomaticZenRule(String oldName, String newName); + boolean removeAutomaticZenRule(String name); byte[] getBackupPayload(int user); void applyRestore(in byte[] payload, int user); diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 605c00613087..cbf198bb9415 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -420,6 +420,106 @@ public class NotificationManager } /** + * Returns AutomaticZenRules owned by the caller. + * + * <p> + * Only available if policy access is granted to this package. + * See {@link #isNotificationPolicyAccessGranted}. + */ + public List<AutomaticZenRule> getAutomaticZenRules() { + INotificationManager service = getService(); + try { + return service.getAutomaticZenRules(); + } catch (RemoteException e) { + } + return null; + } + + /** + * Returns the AutomaticZenRule with the given name, if it exists and the caller has access. + * + * <p> + * Only available if policy access is granted to this package. + * See {@link #isNotificationPolicyAccessGranted}. + * + * <p> + * Returns null if there are no zen rules that match the given name, or if the calling package + * doesn't own the matching rule. See {@link AutomaticZenRule#getOwner}. + */ + public AutomaticZenRule getAutomaticZenRule(String name) { + INotificationManager service = getService(); + try { + return service.getAutomaticZenRule(name); + } catch (RemoteException e) { + } + return null; + } + + /** + * Creates or updates the given zen rule. + * + * <p> + * Only available if policy access is granted to this package. + * See {@link #isNotificationPolicyAccessGranted}. + * + * <p> + * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}. + * @param automaticZenRule the rule to create or update. + * @return Whether the rule was successfully created or updated. + */ + public boolean addOrUpdateAutomaticZenRule(AutomaticZenRule automaticZenRule) { + INotificationManager service = getService(); + try { + return service.addOrUpdateAutomaticZenRule(automaticZenRule); + } catch (RemoteException e) { + } + return false; + } + + /** + * Renames a zen rule. + * + * <p> + * Only available if policy access is granted to this package. + * See {@link #isNotificationPolicyAccessGranted}. + * + * <p> + * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}. + * @param oldName The name of the rule to update. + * @param newName The new name for the rule. + * @return Whether the rule was successfully updated. + */ + public boolean renameAutomaticZenRule(String oldName, String newName) { + INotificationManager service = getService(); + try { + return service.renameAutomaticZenRule(oldName, newName); + } catch (RemoteException e) { + } + return false; + } + + /** + * Deletes the automatic zen rule with the given name. + * + * <p> + * Only available if policy access is granted to this package. + * See {@link #isNotificationPolicyAccessGranted}. + * + * <p> + * Callers can only delete rules that they own. See {@link AutomaticZenRule#getOwner}. + * @param name the name of the rule to delete. + * @return Whether the rule was successfully deleted. + */ + public boolean removeAutomaticZenRule(String name) { + INotificationManager service = getService(); + try { + return service.removeAutomaticZenRule(name); + } catch (RemoteException e) { + } + return false; + } + + /** * Checks the ability to read/modify notification policy for the calling package. * * <p> diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 31d1ab7b92ac..5e8ad68957b2 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -90,6 +90,9 @@ public class StatusBarManager { public static final int WINDOW_STATE_HIDING = 1; public static final int WINDOW_STATE_HIDDEN = 2; + public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0; + public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1; + private Context mContext; private IStatusBarService mService; private IBinder mToken = new Binder(); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index e6484e965ee0..a118f167ae5c 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2438,6 +2438,17 @@ public class DevicePolicyManager { } /** + * Determine whether or not creating a guest user has been disabled for the device + * + * @hide + */ + public boolean getGuestUserDisabled(@Nullable ComponentName admin) { + // Currently guest users can always be created if multi-user is enabled + // TODO introduce a policy for guest user creation + return false; + } + + /** * Called by a device/profile owner to set whether the screen capture is disabled. Disabling * screen capture also prevents the content from being shown on display devices that do not have * a secure video output. See {@link android.view.Display#FLAG_SECURE} for more details about diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 689283c8e550..aa4a631ea76a 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -533,6 +533,14 @@ public abstract class BackupAgent extends ContextWrapper { File file = scanQueue.remove(0); String filePath; try { + // Ignore symlinks outright + StructStat stat = Os.lstat(file.getPath()); + if (OsConstants.S_ISLNK(stat.st_mode)) { + if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file); + continue; + } + + // For all other verification, look at the canonicalized path filePath = file.getCanonicalPath(); // prune this subtree? @@ -544,11 +552,7 @@ public abstract class BackupAgent extends ContextWrapper { } // If it's a directory, enqueue its contents for scanning. - StructStat stat = Os.lstat(filePath); - if (OsConstants.S_ISLNK(stat.st_mode)) { - if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file); - continue; - } else if (OsConstants.S_ISDIR(stat.st_mode)) { + if (OsConstants.S_ISDIR(stat.st_mode)) { File[] contents = file.listFiles(); if (contents != null) { for (File entry : contents) { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index b08db20c2eea..670ca803a367 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3033,6 +3033,39 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY"; + /** + * Broadcast action: reports when a new thermal event has been reached. When the device + * is reaching its maximum temperatue, the thermal level reported + * {@hide} + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_THERMAL_EVENT = "android.intent.action.THERMAL_EVENT"; + + /** {@hide} */ + public static final String EXTRA_THERMAL_STATE = "android.intent.extra.THERMAL_STATE"; + + /** + * Thermal state when the device is normal. This state is sent in the + * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}. + * {@hide} + */ + public static final int EXTRA_THERMAL_STATE_NORMAL = 0; + + /** + * Thermal state where the device is approaching its maximum threshold. This state is sent in + * the {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}. + * {@hide} + */ + public static final int EXTRA_THERMAL_STATE_WARNING = 1; + + /** + * Thermal state where the device has reached its maximum threshold. This state is sent in the + * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}. + * {@hide} + */ + public static final int EXTRA_THERMAL_STATE_EXCEEDED = 2; + + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index c8e9402e6442..697b946eec73 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2010,7 +2010,7 @@ public abstract class PackageManager { * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, * {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to * modify the data returned. - * @return Returns a PackageInfo object containing information about the + * @return A PackageInfo object containing information about the * package. If flag GET_UNINSTALLED_PACKAGES is set and if the * package is not found in the list of installed applications, the * package information is retrieved from the list of uninstalled @@ -2032,6 +2032,46 @@ public abstract class PackageManager { throws NameNotFoundException; /** + * @hide + * Retrieve overall information about an application package that is + * installed on the system. + * <p> + * Throws {@link NameNotFoundException} if a package with the given name can + * not be found on the system. + * + * @param packageName The full name (i.e. com.google.apps.contacts) of the + * desired package. + * @param flags Additional option flags. Use any combination of + * {@link #GET_ACTIVITIES}, {@link #GET_GIDS}, + * {@link #GET_CONFIGURATIONS}, {@link #GET_INSTRUMENTATION}, + * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, + * {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to + * modify the data returned. + * @param userId The user id. + * @return A PackageInfo object containing information about the + * package. If flag GET_UNINSTALLED_PACKAGES is set and if the + * package is not found in the list of installed applications, the + * package information is retrieved from the list of uninstalled + * applications (which includes installed applications as well as + * applications with data directory i.e. applications which had been + * deleted with {@code DONT_DELETE_DATA} flag set). + * @see #GET_ACTIVITIES + * @see #GET_GIDS + * @see #GET_CONFIGURATIONS + * @see #GET_INSTRUMENTATION + * @see #GET_PERMISSIONS + * @see #GET_PROVIDERS + * @see #GET_RECEIVERS + * @see #GET_SERVICES + * @see #GET_SIGNATURES + * @see #GET_UNINSTALLED_PACKAGES + */ + @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) + public abstract PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) + throws NameNotFoundException; + + /** * Map from the current package names in use on the device to whatever * the current canonical name of that package is. * @param names Array of current names to be mapped. @@ -3689,6 +3729,31 @@ public abstract class PackageManager { Uri packageURI, PackageInstallObserver observer, int flags, String installerPackageName); + + /** + * @hide + * Install a package. Since this may take a little while, the result will be + * posted back to the given observer. An installation will fail if the package named + * in the package file's manifest is already installed, or if there's no space + * available on the device. + * @param packageURI The location of the package file to install. This can be a 'file:' or a + * 'content:' URI. + * @param observer An observer callback to get notified when the package installation is + * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be + * called when that happens. This parameter must not be null. + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that is performing the + * installation. This identifies which market the package came from. + * @param userId The user id. + */ + @RequiresPermission(anyOf = { + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.INTERACT_ACROSS_USERS_FULL}) + public abstract void installPackageAsUser( + Uri packageURI, PackageInstallObserver observer, int flags, + String installerPackageName, int userId); + /** * Similar to * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but @@ -3752,7 +3817,17 @@ public abstract class PackageManager { * @hide */ // @SystemApi - public abstract int installExistingPackage(String packageName) + public abstract int installExistingPackage(String packageName) throws NameNotFoundException; + + /** + * If there is already an application with the given package name installed + * on the system for other users, also install it for the specified user. + * @hide + */ + @RequiresPermission(anyOf = { + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.INTERACT_ACROSS_USERS_FULL}) + public abstract int installExistingPackageAsUser(String packageName, int userId) throws NameNotFoundException; /** @@ -3958,7 +4033,7 @@ public abstract class PackageManager { * @param observer An observer callback to get notified when the package deletion is * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be * called when that happens. observer may be null to indicate that no callback is desired. - * @param flags - possible values: {@link #DELETE_KEEP_DATA}, + * @param flags Possible values: {@link #DELETE_KEEP_DATA}, * {@link #DELETE_ALL_USERS}. * * @hide @@ -3968,6 +4043,27 @@ public abstract class PackageManager { String packageName, IPackageDeleteObserver observer, int flags); /** + * Attempts to delete a package. Since this may take a little while, the result will + * be posted back to the given observer. A deletion will fail if the named package cannot be + * found, or if the named package is a "system package". + * (TODO: include pointer to documentation on "system packages") + * + * @param packageName The name of the package to delete + * @param observer An observer callback to get notified when the package deletion is + * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be + * called when that happens. observer may be null to indicate that no callback is desired. + * @param flags Possible values: {@link #DELETE_KEEP_DATA}, {@link #DELETE_ALL_USERS}. + * @param userId The user Id + * + * @hide + */ + @RequiresPermission(anyOf = { + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.INTERACT_ACROSS_USERS_FULL}) + public abstract void deletePackageAsUser( + String packageName, IPackageDeleteObserver observer, int flags, int userId); + + /** * Retrieve the package name of the application that installed a package. This identifies * which market the package came from. * diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 73925633f741..d7c221510942 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -136,7 +136,16 @@ public class UserInfo implements Parcelable { * the method always returns false. */ public boolean isSystemOnly() { - return id == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser(); + return isSystemOnly(id); + } + + /** + * Returns true if the given user is a split system user. + * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled, + * the method always returns false. + */ + public static boolean isSystemOnly(int userId) { + return userId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser(); } /** diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index e29bd2cc53e0..0606e35a081e 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -16,24 +16,14 @@ package android.content.res; -import android.annotation.AttrRes; -import android.annotation.ColorInt; -import android.annotation.StyleRes; -import android.annotation.StyleableRes; -import android.graphics.drawable.DrawableInflater; -import android.icu.text.PluralRules; -import com.android.internal.util.GrowingArrayUtils; -import com.android.internal.util.XmlUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.animation.Animator; import android.animation.StateListAnimator; import android.annotation.AnimRes; import android.annotation.AnyRes; import android.annotation.ArrayRes; +import android.annotation.AttrRes; import android.annotation.BoolRes; +import android.annotation.ColorInt; import android.annotation.ColorRes; import android.annotation.DimenRes; import android.annotation.DrawableRes; @@ -45,18 +35,23 @@ import android.annotation.Nullable; import android.annotation.PluralsRes; import android.annotation.RawRes; import android.annotation.StringRes; +import android.annotation.StyleRes; +import android.annotation.StyleableRes; import android.annotation.XmlRes; import android.content.pm.ActivityInfo; import android.graphics.Movie; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable.ConstantState; +import android.graphics.drawable.DrawableInflater; +import android.icu.text.PluralRules; import android.os.Build; import android.os.Bundle; import android.os.Trace; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.DisplayMetrics; +import android.util.LocaleList; import android.util.Log; import android.util.LongSparseArray; import android.util.Pools.SynchronizedPool; @@ -65,6 +60,12 @@ import android.util.TypedValue; import android.view.ViewDebug; import android.view.ViewHierarchyEncoder; +import com.android.internal.util.GrowingArrayUtils; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; @@ -372,7 +373,7 @@ public class Resources { private PluralRules getPluralRule() { synchronized (sSync) { if (mPluralRule == null) { - mPluralRule = PluralRules.forLocale(mConfiguration.locale); + mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary()); } return mPluralRule; } @@ -435,7 +436,7 @@ public class Resources { @NonNull public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException { final String raw = getString(id); - return String.format(mConfiguration.locale, raw, formatArgs); + return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs); } /** @@ -466,7 +467,7 @@ public class Resources { public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs) throws NotFoundException { String raw = getQuantityText(id, quantity).toString(); - return String.format(mConfiguration.locale, raw, formatArgs); + return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs); } /** @@ -1971,9 +1972,10 @@ public class Resources { mCompatibilityInfo.applyToDisplayMetrics(mMetrics); final int configChanges = calcConfigChanges(config); - if (mConfiguration.locale == null) { - mConfiguration.locale = Locale.getDefault(); - mConfiguration.setLayoutDirection(mConfiguration.locale); + LocaleList locales = mConfiguration.getLocales(); + if (locales.isEmpty()) { + locales = LocaleList.getDefault(); + mConfiguration.setLocales(locales); } if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) { mMetrics.densityDpi = mConfiguration.densityDpi; @@ -1981,11 +1983,6 @@ public class Resources { } mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; - String locale = null; - if (mConfiguration.locale != null) { - locale = adjustLanguageTag(mConfiguration.locale.toLanguageTag()); - } - final int width, height; if (mMetrics.widthPixels >= mMetrics.heightPixels) { width = mMetrics.widthPixels; @@ -2005,8 +2002,10 @@ public class Resources { keyboardHidden = mConfiguration.keyboardHidden; } + // TODO: Pass the whole locale list to setConfiguration() mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc, - locale, mConfiguration.orientation, + adjustLanguageTag(locales.getPrimary().toLanguageTag()), + mConfiguration.orientation, mConfiguration.touchscreen, mConfiguration.densityDpi, mConfiguration.keyboard, keyboardHidden, mConfiguration.navigation, width, height, @@ -2030,7 +2029,7 @@ public class Resources { } synchronized (sSync) { if (mPluralRule != null) { - mPluralRule = PluralRules.forLocale(config.locale); + mPluralRule = PluralRules.forLocale(config.getLocales().getPrimary()); } } } @@ -2049,9 +2048,8 @@ public class Resources { mCompatibilityInfo.applyToConfiguration(density, mTmpConfig); - if (mTmpConfig.locale == null) { - mTmpConfig.locale = Locale.getDefault(); - mTmpConfig.setLayoutDirection(mTmpConfig.locale); + if (mTmpConfig.getLocales().isEmpty()) { + mTmpConfig.setLocales(LocaleList.getDefault()); } configChanges = mConfiguration.updateFrom(mTmpConfig); configChanges = ActivityInfo.activityInfoConfigToNative(configChanges); diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 9a2a24128b92..444548faad42 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -208,6 +208,12 @@ public class ConnectivityManager { * {@link android.content.Intent#getParcelableExtra(String)}. */ public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL"; + + /** + * Key for passing a URL to the captive portal login activity. + */ + public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL"; + /** * Broadcast action to indicate the change of data activity status * (idle or active) on a network in a recent period. diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index cfa6164b0454..c4501bade098 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -157,7 +157,7 @@ public class Binder implements IBinder { * incoming transaction, then its own UserHandle is returned. */ public static final UserHandle getCallingUserHandle() { - return new UserHandle(UserHandle.getUserId(getCallingUid())); + return UserHandle.of(UserHandle.getUserId(getCallingUid())); } /** diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index c4f62baab4a1..9fdbec39b2bd 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -23,8 +23,11 @@ import android.os.WorkSource; interface IPowerManager { - // WARNING: The first five methods must remain the first five methods because their - // transaction numbers must not change unless IPowerManager.cpp is also updated. + // WARNING: When methods are inserted or deleted, the transaction IDs in + // frameworks/native/include/powermanager/IPowerManager.h must be updated to match the order in this file. + // + // When a method's argument list is changed, BnPowerManager's corresponding serialization code (if any) in + // frameworks/native/services/powermanager/IPowerManager.cpp must be updated. void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws, String historyTag); void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName, diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index aeb5d4517e6c..4c19ddda19bd 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -35,6 +35,7 @@ interface IUserManager { UserInfo createUser(in String name, int flags); UserInfo createProfileForUser(in String name, int flags, int userHandle); + UserInfo createRestrictedProfile(String name, int parentUserId); void setUserEnabled(int userHandle); boolean removeUser(int userHandle); void setUserName(int userHandle, String name); @@ -48,6 +49,7 @@ interface IUserManager { UserInfo getUserInfo(int userHandle); long getUserCreationTime(int userHandle); boolean isRestricted(); + boolean canHaveRestrictedProfile(int userId); int getUserSerialNumber(int userHandle); int getUserHandle(int userSerialNumber); Bundle getUserRestrictions(int userHandle); diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 7234e985757a..4ac361d00682 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -797,8 +797,8 @@ public class Process { * {@link #myUid()} in that a particular user will have multiple * distinct apps running under it each with their own uid. */ - public static final UserHandle myUserHandle() { - return new UserHandle(UserHandle.getUserId(myUid())); + public static UserHandle myUserHandle() { + return UserHandle.of(UserHandle.getUserId(myUid())); } /** diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 87ce12cbe37c..8b2c74f07598 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -1923,7 +1923,7 @@ public final class StrictMode { if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call. i=" + i); ViolationInfo info = new ViolationInfo(p, !currentlyGathering); if (info.crashInfo.stackTrace != null && info.crashInfo.stackTrace.length() > 30000) { - String front = info.crashInfo.stackTrace.substring(256); + String front = info.crashInfo.stackTrace.substring(0, 256); // 30000 characters is way too large for this to be any sane kind of // strict mode collection of stacks. We've had a problem where we leave // strict mode violations associated with the thread, and it keeps tacking diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index 213e0831c0f2..796addc4c3bc 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -17,7 +17,6 @@ package android.os; import android.annotation.SystemApi; -import android.util.SparseArray; import java.io.PrintWriter; @@ -83,8 +82,6 @@ public final class UserHandle implements Parcelable { final int mHandle; - private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>(); - /** * Checks to see if the user id is the same for the two uids, i.e., they belong to the same * user. @@ -144,15 +141,8 @@ public final class UserHandle implements Parcelable { } /** @hide */ - public static UserHandle getCallingUserHandle() { - int userId = getUserId(Binder.getCallingUid()); - UserHandle userHandle = userHandles.get(userId); - // Intentionally not synchronized to save time - if (userHandle == null) { - userHandle = new UserHandle(userId); - userHandles.put(userId, userHandle); - } - return userHandle; + public static UserHandle of(int userId) { + return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId); } /** diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 64e2505b5006..d178d20ac14c 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -15,10 +15,12 @@ */ package android.os; +import android.accounts.AccountManager; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.pm.UserInfo; import android.content.res.Resources; @@ -631,6 +633,19 @@ public class UserManager { } /** + * Checks if specified user can have restricted profile. + * @hide + */ + public boolean canHaveRestrictedProfile(int userId) { + try { + return mService.canHaveRestrictedProfile(userId); + } catch (RemoteException re) { + Log.w(TAG, "Could not check if user can have restricted profile", re); + return false; + } + } + + /** * Checks if the calling app is running as a guest user. * @return whether the caller is a guest user. * @hide @@ -927,7 +942,8 @@ public class UserManager { } /** - * Creates a restricted profile with the specified name. + * Creates a restricted profile with the specified name. This method also sets necessary + * restrictions and adds shared accounts. * * @param name profile's name * @return UserInfo object for the created user, or null if the user could not be created. @@ -935,13 +951,14 @@ public class UserManager { */ public UserInfo createRestrictedProfile(String name) { try { - if (isSplitSystemUser()) { - return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED, - UserHandle.getCallingUserId()); - } else { - return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED, - UserHandle.USER_SYSTEM); + UserHandle parentUserHandle = Process.myUserHandle(); + UserInfo user = mService.createRestrictedProfile(name, + parentUserHandle.getIdentifier()); + if (user != null) { + AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle, + UserHandle.of(user.id)); } + return user; } catch (RemoteException e) { Log.w(TAG, "Could not create a restricted profile", e); } @@ -1321,12 +1338,15 @@ public class UserManager { } /** - * Returns true if the user switcher should be shown, this will be if there - * are multiple users that aren't managed profiles. + * Returns true if the user switcher should be shown, this will be if device supports multi-user + * and there are at least 2 users available that are not managed profiles. * @hide * @return true if user switcher should be shown. */ public boolean isUserSwitcherEnabled() { + if (!supportsMultipleUsers()) { + return false; + } List<UserInfo> users = getUsers(true); if (users == null) { return false; @@ -1337,8 +1357,8 @@ public class UserManager { ++switchableUserCount; } } - final boolean guestEnabled = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.GUEST_USER_ENABLED, 0) == 1; + final boolean guestEnabled = !mContext.getSystemService(DevicePolicyManager.class) + .getGuestUserDisabled(null); return switchableUserCount > 1 || guestEnabled; } diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java index 688859479713..c368e5a24a1b 100644 --- a/core/java/android/os/storage/VolumeInfo.java +++ b/core/java/android/os/storage/VolumeInfo.java @@ -438,6 +438,8 @@ public class VolumeInfo implements Parcelable { final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setData(uri); + intent.putExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, true); + intent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true); return intent; } diff --git a/core/java/android/preference/SeekBarPreference.java b/core/java/android/preference/SeekBarPreference.java index 67f64090db16..5414f0007970 100644 --- a/core/java/android/preference/SeekBarPreference.java +++ b/core/java/android/preference/SeekBarPreference.java @@ -96,18 +96,15 @@ public class SeekBarPreference extends Preference @Override public boolean onKey(View v, int keyCode, KeyEvent event) { - if (event.getAction() != KeyEvent.ACTION_UP) { - if (keyCode == KeyEvent.KEYCODE_PLUS - || keyCode == KeyEvent.KEYCODE_EQUALS) { - setProgress(getProgress() + 1); - return true; - } - if (keyCode == KeyEvent.KEYCODE_MINUS) { - setProgress(getProgress() - 1); - return true; - } + if (event.getAction() != KeyEvent.ACTION_DOWN) { + return false; + } + + SeekBar seekBar = (SeekBar) v.findViewById(com.android.internal.R.id.seekbar); + if (seekBar == null) { + return false; } - return false; + return seekBar.onKeyDown(keyCode, event); } public void setMax(int max) { diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 59609f94546a..1b104e3500ff 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -93,6 +93,9 @@ public final class DocumentsContract { public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED"; /** {@hide} */ + public static final String EXTRA_SHOW_FILESIZE = "android.content.extra.SHOW_FILESIZE"; + + /** {@hide} */ public static final String EXTRA_TARGET_URI = "android.content.extra.TARGET_URI"; /** @@ -133,6 +136,9 @@ public final class DocumentsContract { */ private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES); + /** {@hide} */ + public static final String PACKAGE_DOCUMENTS_UI = "com.android.documentsui"; + /** * Constants related to a document, including {@link Cursor} column names * and flags. @@ -266,7 +272,7 @@ public final class DocumentsContract { * writability of a document may change over time, for example due to * remote access changes. This flag indicates that a document client can * expect {@link ContentResolver#openOutputStream(Uri)} to succeed. - * + * * @see #COLUMN_FLAGS */ public static final int FLAG_SUPPORTS_WRITE = 1 << 1; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 225f0cf97c2e..d601831b863c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7689,14 +7689,6 @@ public final class Settings { public static final String DEVICE_NAME = "device_name"; /** - * Whether it should be possible to create a guest user on the device. - * <p> - * Type: int (0 for disabled, 1 for enabled) - * @hide - */ - public static final String GUEST_USER_ENABLED = "guest_user_enabled"; - - /** * Whether the NetworkScoringService has been first initialized. * <p> * Type: int (0 for false, 1 for true) diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 631057013e50..4de903efff18 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -755,6 +755,10 @@ public class ZenModeConfig implements Parcelable { return rt; } + public static ComponentName getScheduleConditionProvider() { + return new ComponentName(SYSTEM_AUTHORITY, "ScheduleConditionProvider"); + } + public static class ScheduleInfo { public int[] days; public int startHour; @@ -827,6 +831,10 @@ public class ZenModeConfig implements Parcelable { return rt; } + public static ComponentName getEventConditionProvider() { + return new ComponentName(SYSTEM_AUTHORITY, "EventConditionProvider"); + } + public static class EventInfo { public static final int REPLY_ANY_EXCEPT_NO = 0; public static final int REPLY_YES_OR_MAYBE = 1; diff --git a/core/java/android/view/BatchedInputEventReceiver.java b/core/java/android/view/BatchedInputEventReceiver.java new file mode 100644 index 000000000000..b1d28e000bc8 --- /dev/null +++ b/core/java/android/view/BatchedInputEventReceiver.java @@ -0,0 +1,82 @@ +/* + * 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.Looper; + +/** + * Similar to {@link InputEventReceiver}, but batches events to vsync boundaries when possible. + * @hide + */ +public class BatchedInputEventReceiver extends InputEventReceiver { + Choreographer mChoreographer; + private boolean mBatchedInputScheduled; + + public BatchedInputEventReceiver( + InputChannel inputChannel, Looper looper, Choreographer choreographer) { + super(inputChannel, looper); + mChoreographer = choreographer; + } + + @Override + public void onBatchedInputEventPending() { + scheduleBatchedInput(); + } + + @Override + public void dispose() { + unscheduleBatchedInput(); + super.dispose(); + } + + void doConsumeBatchedInput(long frameTimeNanos) { + if (mBatchedInputScheduled) { + mBatchedInputScheduled = false; + if (consumeBatchedInputEvents(frameTimeNanos) && frameTimeNanos != -1) { + // If we consumed a batch here, we want to go ahead and schedule the + // consumption of batched input events on the next frame. Otherwise, we would + // wait until we have more input events pending and might get starved by other + // things occurring in the process. If the frame time is -1, however, then + // we're in a non-batching mode, so there's no need to schedule this. + scheduleBatchedInput(); + } + } + } + + private void scheduleBatchedInput() { + if (!mBatchedInputScheduled) { + mBatchedInputScheduled = true; + mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null); + } + } + + private void unscheduleBatchedInput() { + if (mBatchedInputScheduled) { + mBatchedInputScheduled = false; + mChoreographer.removeCallbacks( + Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null); + } + } + + private final class BatchedInputRunnable implements Runnable { + @Override + public void run() { + doConsumeBatchedInput(mChoreographer.getFrameTimeNanos()); + } + } + private final BatchedInputRunnable mBatchedInputRunnable = new BatchedInputRunnable(); +} diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 32ef99582ac9..7adfa8dbae4f 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -144,7 +144,6 @@ interface IWindowManager void setAppStartingWindow(IBinder token, String pkg, int theme, in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded); - void setAppWillBeHidden(IBinder token); void setAppVisibility(IBinder token, boolean visible); void startAppFreezingScreen(IBinder token, int configChanges); void stopAppFreezingScreen(IBinder token, boolean force); diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 37312d064948..e200bef7ec52 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -72,6 +72,9 @@ public abstract class LayoutInflater { private static final String TAG = LayoutInflater.class.getSimpleName(); private static final boolean DEBUG = false; + /** Empty stack trace used to avoid log spam in re-throw exceptions. */ + private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; + /** * This field should be made private, so it is hidden from the SDK. * {@hide} @@ -532,15 +535,14 @@ public abstract class LayoutInflater { } } catch (XmlPullParserException e) { - InflateException ex = new InflateException(e.getMessage()); - ex.initCause(e); - throw ex; + final InflateException ie = new InflateException(e.getMessage(), e); + ie.setStackTrace(EMPTY_STACK_TRACE); + throw ie; } catch (Exception e) { - InflateException ex = new InflateException( - parser.getPositionDescription() - + ": " + e.getMessage()); - ex.initCause(e); - throw ex; + final InflateException ie = new InflateException(parser.getPositionDescription() + + ": " + e.getMessage(), e); + ie.setStackTrace(EMPTY_STACK_TRACE); + throw ie; } finally { // Don't retain static reference on context. mConstructorArgs[0] = lastContext; @@ -625,27 +627,25 @@ public abstract class LayoutInflater { return view; } catch (NoSuchMethodException e) { - InflateException ie = new InflateException(attrs.getPositionDescription() - + ": Error inflating class " - + (prefix != null ? (prefix + name) : name)); - ie.initCause(e); + final InflateException ie = new InflateException(attrs.getPositionDescription() + + ": Error inflating class " + (prefix != null ? (prefix + name) : name), e); + ie.setStackTrace(EMPTY_STACK_TRACE); throw ie; } catch (ClassCastException e) { // If loaded class is not a View subclass - InflateException ie = new InflateException(attrs.getPositionDescription() - + ": Class is not a View " - + (prefix != null ? (prefix + name) : name)); - ie.initCause(e); + final InflateException ie = new InflateException(attrs.getPositionDescription() + + ": Class is not a View " + (prefix != null ? (prefix + name) : name), e); + ie.setStackTrace(EMPTY_STACK_TRACE); throw ie; } catch (ClassNotFoundException e) { // If loadClass fails, we should propagate the exception. throw e; } catch (Exception e) { - InflateException ie = new InflateException(attrs.getPositionDescription() - + ": Error inflating class " - + (clazz == null ? "<unknown>" : clazz.getName())); - ie.initCause(e); + final InflateException ie = new InflateException( + attrs.getPositionDescription() + ": Error inflating class " + + (clazz == null ? "<unknown>" : clazz.getName()), e); + ie.setStackTrace(EMPTY_STACK_TRACE); throw ie; } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); @@ -657,8 +657,7 @@ public abstract class LayoutInflater { */ private void failNotAllowed(String name, String prefix, AttributeSet attrs) { throw new InflateException(attrs.getPositionDescription() - + ": Class not allowed to be inflated " - + (prefix != null ? (prefix + name) : name)); + + ": Class not allowed to be inflated "+ (prefix != null ? (prefix + name) : name)); } /** @@ -774,14 +773,14 @@ public abstract class LayoutInflater { } catch (ClassNotFoundException e) { final InflateException ie = new InflateException(attrs.getPositionDescription() - + ": Error inflating class " + name); - ie.initCause(e); + + ": Error inflating class " + name, e); + ie.setStackTrace(EMPTY_STACK_TRACE); throw ie; } catch (Exception e) { final InflateException ie = new InflateException(attrs.getPositionDescription() - + ": Error inflating class " + name); - ie.initCause(e); + + ": Error inflating class " + name, e); + ie.setStackTrace(EMPTY_STACK_TRACE); throw ie; } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 2a1d757feb7b..2c7a43648f2c 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5388,7 +5388,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, protected boolean performButtonActionOnTouchDown(MotionEvent event) { if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE && (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { - showContextMenu(event.getX(), event.getY(), event.getMetaState()); + showContextMenu(event.getX(), event.getY()); mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; return true; } @@ -5409,13 +5409,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param x The referenced x coordinate. * @param y The referenced y coordinate. - * @param metaState The keyboard modifiers that were pressed. * @return Whether a context menu was displayed. - * - * @hide */ - public boolean showContextMenu(float x, float y, int metaState) { - return showContextMenu(); + public boolean showContextMenu(float x, float y) { + return getParent().showContextMenuForChild(this, x, y); } /** @@ -6652,12 +6649,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Sets a delegate for implementing accessibility support via composition as - * opposed to inheritance. The delegate's primary use is for implementing - * backwards compatible widgets. For more details see {@link AccessibilityDelegate}. - * - * @param delegate The delegate instance. + * Sets a delegate for implementing accessibility support via composition + * (as opposed to inheritance). For more details, see + * {@link AccessibilityDelegate}. + * <p> + * <strong>Note:</strong> On platform versions prior to + * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on + * views in the {@code android.widget.*} package are called <i>before</i> + * host methods. This prevents certain properties such as class name from + * being modified by overriding + * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, + * as any changes will be overwritten by the host class. + * <p> + * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate + * methods are called <i>after</i> host methods, which all properties to be + * modified without being overwritten by the host class. * + * @param delegate the object to which accessibility method calls should be + * delegated * @see AccessibilityDelegate */ public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { @@ -22280,6 +22289,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * corresponding delegate method without altering the behavior of the rest * accessibility related methods of the host view. * </p> + * <p> + * <strong>Note:</strong> On platform versions prior to + * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on + * views in the {@code android.widget.*} package are called <i>before</i> + * host methods. This prevents certain properties such as class name from + * being modified by overriding + * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, + * as any changes will be overwritten by the host class. + * <p> + * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate + * methods are called <i>after</i> host methods, which all properties to be + * modified without being overwritten by the host class. */ public static class AccessibilityDelegate { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index bdcd998de7c7..475ce2feed50 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -767,6 +767,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mParent != null && mParent.showContextMenuForChild(originalView); } + @Override + public boolean showContextMenuForChild(View originalView, float x, float y) { + return mParent != null && mParent.showContextMenuForChild(originalView, x, y); + } + /** * {@inheritDoc} */ diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index 15b86d1245b2..07f1e2cbdb4f 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -182,6 +182,17 @@ public interface ViewParent { public boolean showContextMenuForChild(View originalView); /** + * Bring up a context menu for the specified view at the given x/y offset from + * the top left corner. + * + * @param originalView + * @param x The x offset at which to open the menu + * @param y The y offset at which to open the menu + * @return true if a context menu was displayed + */ + public boolean showContextMenuForChild(View originalView, float x, float y); + + /** * Have the parent populate the specified context menu if it has anything to * add (and then recurse on its parent). * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 8403c46e85bc..f6c60ed688a5 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6240,6 +6240,11 @@ public final class ViewRootImpl implements ViewParent, } @Override + public boolean showContextMenuForChild(View originalView, float x, float y) { + return false; + } + + @Override public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { return null; } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 0e7089ff7a8c..5f4e7af9390e 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -2016,4 +2016,8 @@ public abstract class Window { public boolean hasNonClientDecorView() { return false; } + + /** @hide */ + public void setTheme(int resId) { + } } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 45bc1df33469..92e473db556f 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -226,6 +226,7 @@ public interface WindowManager extends ViewManager { @ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION"), @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION, to = "TYPE_VOICE_INTERACTION"), @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"), + @ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER, to = "TYPE_DOCK_DIVIDER"), }) public int type; @@ -565,6 +566,13 @@ public interface WindowManager extends ViewManager { public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33; /** + * Window for displaying a handle used for resizing docked stacks. This window is owned + * by the system process. + * @hide + */ + public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34; + + /** * End of types of system windows. */ public static final int LAST_SYSTEM_WINDOW = 2999; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 5724f526918b..b8faf0c6cf98 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3080,6 +3080,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } private class CheckForLongPress extends WindowRunnnable implements Runnable { + private static final int INVALID_COORD = -1; + private float mX = INVALID_COORD; + private float mY = INVALID_COORD; + + private void setCoords(float x, float y) { + mX = x; + mY = y; + } + @Override public void run() { final int motionPosition = mMotionPosition; @@ -3090,7 +3099,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te boolean handled = false; if (sameWindow() && !mDataChanged) { - handled = performLongPress(child, longPressPosition, longPressId); + if (mX != INVALID_COORD && mY != INVALID_COORD) { + handled = performLongPress(child, longPressPosition, longPressId, mX, mY); + } else { + handled = performLongPress(child, longPressPosition, longPressId); + } } if (handled) { mTouchMode = TOUCH_MODE_REST; @@ -3146,6 +3159,16 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te boolean performLongPress(final View child, final int longPressPosition, final long longPressId) { + return performLongPress( + child, + longPressPosition, + longPressId, + CheckForLongPress.INVALID_COORD, + CheckForLongPress.INVALID_COORD); + } + + boolean performLongPress(final View child, + final int longPressPosition, final long longPressId, float x, float y) { // CHOICE_MODE_MULTIPLE_MODAL takes over long press. if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) { if (mChoiceActionMode == null && @@ -3163,7 +3186,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } if (!handled) { mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId); - handled = super.showContextMenuForChild(AbsListView.this); + if (x != CheckForLongPress.INVALID_COORD && y != CheckForLongPress.INVALID_COORD) { + handled = super.showContextMenuForChild(AbsListView.this, x, y); + } else { + handled = super.showContextMenuForChild(AbsListView.this); + } } if (handled) { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -3178,17 +3205,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te /** @hide */ @Override - public boolean showContextMenu(float x, float y, int metaState) { + public boolean showContextMenu(float x, float y) { final int position = pointToPosition((int)x, (int)y); if (position != INVALID_POSITION) { final long id = mAdapter.getItemId(position); View child = getChildAt(position - mFirstPosition); if (child != null) { mContextMenuInfo = createContextMenuInfo(child, position, id); - return super.showContextMenuForChild(AbsListView.this); + return super.showContextMenuForChild(AbsListView.this, x, y); } } - return super.showContextMenu(x, y, metaState); + return super.showContextMenu(x, y); } @Override @@ -3341,6 +3368,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (mPendingCheckForLongPress == null) { mPendingCheckForLongPress = new CheckForLongPress(); } + mPendingCheckForLongPress.setCoords(x, y); mPendingCheckForLongPress.rememberWindowAttachCount(); postDelayed(mPendingCheckForLongPress, longPressTimeout); } else { diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 68855ff72531..10aefe4eb714 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -666,7 +666,7 @@ public abstract class AbsSeekBar extends ProgressBar { progress += scale * max; setHotspot(x, (int) event.getY()); - setProgress((int) progress, true); + setProgressInternal((int) progress, true, false); } /** @@ -706,9 +706,12 @@ public abstract class AbsSeekBar extends ProgressBar { int increment = mKeyProgressIncrement; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: + case KeyEvent.KEYCODE_MINUS: increment = -increment; // fallthrough case KeyEvent.KEYCODE_DPAD_RIGHT: + case KeyEvent.KEYCODE_PLUS: + case KeyEvent.KEYCODE_EQUALS: increment = isLayoutRtl() ? -increment : increment; if (setProgressInternal(getProgress() + increment, true, true)) { diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index fddc40fc77b7..f53aa38a4c7a 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -2645,6 +2645,8 @@ public class Editor { private SuggestionAdapter mSuggestionsAdapter; private final Comparator<SuggestionSpan> mSuggestionSpanComparator; private final HashMap<SuggestionSpan, Integer> mSpansLengths; + private final TextAppearanceSpan mHighlightSpan = new TextAppearanceSpan( + mTextView.getContext(), android.R.style.TextAppearance_SuggestionHighlight); private class CustomPopupWindow extends PopupWindow { public CustomPopupWindow(Context context, int defStyleAttr) { @@ -2710,8 +2712,6 @@ public class Editor { SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents int suggestionIndex; // the index of this suggestion inside suggestionSpan SpannableStringBuilder text = new SpannableStringBuilder(); - TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mTextView.getContext(), - android.R.style.TextAppearance_SuggestionHighlight); } private class SuggestionAdapter extends BaseAdapter { @@ -2948,7 +2948,7 @@ public class Editor { suggestionInfo.suggestionIndex = ADD_TO_DICTIONARY; suggestionInfo.text.replace(0, suggestionInfo.text.length(), mTextView. getContext().getString(com.android.internal.R.string.addToDictionary)); - suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0, 0, + suggestionInfo.text.setSpan(mHighlightSpan, 0, 0, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mNumberOfSuggestions++; @@ -2961,8 +2961,7 @@ public class Editor { suggestionInfo.suggestionIndex = DELETE_TEXT; suggestionInfo.text.replace(0, suggestionInfo.text.length(), mTextView.getContext().getString(com.android.internal.R.string.deleteText)); - suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0, 0, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + suggestionInfo.text.setSpan(mHighlightSpan, 0, 0, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mNumberOfSuggestions++; if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan(); @@ -2993,8 +2992,8 @@ public class Editor { suggestionInfo.suggestionEnd = suggestionInfo.suggestionStart + suggestionInfo.text.length(); - suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0, - suggestionInfo.text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + suggestionInfo.text.setSpan(mHighlightSpan, 0, suggestionInfo.text.length(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // Add the text before and after the span. final String textAsString = text.toString(); diff --git a/core/java/android/widget/MenuPopupWindow.java b/core/java/android/widget/MenuPopupWindow.java index ba77b1b53079..1fb62d0fa6c9 100644 --- a/core/java/android/widget/MenuPopupWindow.java +++ b/core/java/android/widget/MenuPopupWindow.java @@ -124,8 +124,8 @@ public class MenuPopupWindow extends ListPopupWindow implements MenuItemHoverLis } return true; } else if (selectedItem != null && keyCode == mRetreatKey) { - setSelectedPositionInt(-1); - setNextSelectedPositionInt(-1); + setSelectedPositionInt(INVALID_POSITION); + setNextSelectedPositionInt(INVALID_POSITION); ((MenuAdapter) getAdapter()).getAdapterMenu().close(); return true; @@ -152,13 +152,19 @@ public class MenuPopupWindow extends ListPopupWindow implements MenuItemHoverLis boolean superVal = super.onHoverEvent(ev); if (dispatchHover && mHoverListener != null) { - mHoverListener.onItemHovered( - ((MenuAdapter) getAdapter()).getAdapterMenu(), position); + ListAdapter adapter = getAdapter(); + MenuAdapter menuAdapter; + if (adapter instanceof HeaderViewListAdapter) { + menuAdapter = (MenuAdapter) ((HeaderViewListAdapter) adapter) + .getWrappedAdapter(); + } else { + menuAdapter = (MenuAdapter) adapter; + } + + mHoverListener.onItemHovered(menuAdapter.getAdapterMenu(), position); } return superVal; } } - - }
\ No newline at end of file diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index f9fa0272f147..7b9de7967db3 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -18,6 +18,7 @@ package android.widget; import com.android.internal.R; +import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; @@ -1449,11 +1450,13 @@ public class PopupWindow { anchor.getLocationOnScreen(mScreenLocation); onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) < (mScreenLocation[1] - yoff - displayFrame.top); - if (onTop) { - p.gravity = Gravity.LEFT | Gravity.BOTTOM; - p.y = root.getHeight() - mDrawingLocation[1] + yoff; - } else { - p.y = mDrawingLocation[1] + anchorHeight + yoff; + if (!mOverlapAnchor) { + if (onTop) { + p.gravity = Gravity.LEFT | Gravity.BOTTOM; + p.y = root.getHeight() - mDrawingLocation[1] + yoff; + } else { + p.y = mDrawingLocation[1] + anchorHeight + yoff; + } } } @@ -1469,13 +1472,21 @@ public class PopupWindow { p.width = Math.min(p.width, displayFrameWidth); } - if (onTop) { - final int popupTop = mScreenLocation[1] + yoff - mPopupHeight; - if (popupTop < 0) { - p.y += popupTop; + if (mOverlapAnchor) { + final int displayFrameHeight = displayFrame.bottom - displayFrame.top; + final int bottom = p.y + p.height; + if (bottom > displayFrame.bottom) { + p.y -= bottom - displayFrameHeight; } } else { - p.y = Math.max(p.y, displayFrame.top); + if (onTop) { + final int popupTop = mScreenLocation[1] + yoff - mPopupHeight; + if (popupTop < 0) { + p.y += popupTop; + } + } else { + p.y = Math.max(p.y, displayFrame.top); + } } } @@ -1494,7 +1505,7 @@ public class PopupWindow { * @return The maximum available height for the popup to be completely * shown. */ - public int getMaxAvailableHeight(View anchor) { + public int getMaxAvailableHeight(@NonNull View anchor) { return getMaxAvailableHeight(anchor, 0); } @@ -1509,7 +1520,7 @@ public class PopupWindow { * @return The maximum available height for the popup to be completely * shown. */ - public int getMaxAvailableHeight(View anchor, int yOffset) { + public int getMaxAvailableHeight(@NonNull View anchor, int yOffset) { return getMaxAvailableHeight(anchor, yOffset, false); } @@ -1527,22 +1538,29 @@ public class PopupWindow { * bottom decorations * @return The maximum available height for the popup to be completely * shown. - * - * @hide Pending API council approval. */ - public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) { + public int getMaxAvailableHeight( + @NonNull View anchor, int yOffset, boolean ignoreBottomDecorations) { final Rect displayFrame = new Rect(); anchor.getWindowVisibleDisplayFrame(displayFrame); final int[] anchorPos = mDrawingLocation; anchor.getLocationOnScreen(anchorPos); - int bottomEdge = displayFrame.bottom; + final int bottomEdge; if (ignoreBottomDecorations) { - Resources res = anchor.getContext().getResources(); + final Resources res = anchor.getContext().getResources(); bottomEdge = res.getDisplayMetrics().heightPixels; + } else { + bottomEdge = displayFrame.bottom; + } + + final int distanceToBottom; + if (mOverlapAnchor) { + distanceToBottom = bottomEdge - anchorPos[1] - yOffset; + } else { + distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset; } - final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset; final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset; // anchorPos[1] is distance from anchor to top of screen diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 7ca333947918..ca1b211bc291 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -31,6 +31,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -55,6 +56,8 @@ import android.view.ViewGroup; import android.widget.AdapterView.OnItemClickListener; import libcore.util.Objects; +import com.android.internal.R; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -206,14 +209,22 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public static class OnClickHandler { + + private int mEnterAnimationId; + public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) { try { // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? Context context = view.getContext(); - ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view, - 0, 0, - view.getMeasuredWidth(), view.getMeasuredHeight()); + ActivityOptions opts; + if (mEnterAnimationId != 0) { + opts = ActivityOptions.makeCustomAnimation(context, mEnterAnimationId, 0); + } else { + opts = ActivityOptions.makeScaleUpAnimation(view, + 0, 0, + view.getMeasuredWidth(), view.getMeasuredHeight()); + } context.startIntentSender( pendingIntent.getIntentSender(), fillInIntent, Intent.FLAG_ACTIVITY_NEW_TASK, @@ -228,6 +239,10 @@ public class RemoteViews implements Parcelable, Filter { } return true; } + + public void setEnterAnimationId(int enterAnimationId) { + mEnterAnimationId = enterAnimationId; + } } /** @@ -2761,11 +2776,31 @@ public class RemoteViews implements Parcelable, Filter { inflater.setFilter(this); result = inflater.inflate(rvToApply.getLayoutId(), parent, false); + loadTransitionOverride(context, handler); + rvToApply.performApply(result, parent, handler); return result; } + private static void loadTransitionOverride(Context context, + RemoteViews.OnClickHandler handler) { + if (handler != null && context.getResources().getBoolean( + com.android.internal.R.bool.config_overrideRemoteViewsActivityTransition)) { + TypedArray windowStyle = context.getTheme().obtainStyledAttributes( + com.android.internal.R.styleable.Window); + int windowAnimations = windowStyle.getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, 0); + TypedArray windowAnimationStyle = context.obtainStyledAttributes( + windowAnimations, com.android.internal.R.styleable.WindowAnimation); + handler.setEnterAnimationId(windowAnimationStyle.getResourceId( + com.android.internal.R.styleable. + WindowAnimation_activityOpenRemoteViewsEnterAnimation, 0)); + windowStyle.recycle(); + windowAnimationStyle.recycle(); + } + } + /** * Applies all of the actions to the provided view. * diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index 6f3a711c8aff..434516da1346 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -1387,7 +1387,7 @@ public class Switch extends CompoundButton { mTrackDrawable.jumpToCurrentState(); } - if (mPositionAnimator != null && mPositionAnimator.isRunning()) { + if (mPositionAnimator != null && mPositionAnimator.isStarted()) { mPositionAnimator.end(); mPositionAnimator = null; } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 2172b5c57893..f0e216fc7873 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -40,6 +40,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; import android.os.UserManager; +import android.provider.DocumentsContract; import android.service.chooser.ChooserTarget; import android.service.chooser.ChooserTargetService; import android.service.chooser.IChooserTargetResult; @@ -269,7 +270,20 @@ public class ChooserActivity extends ResolverActivity { } @Override - boolean shouldAutoLaunchSingleChoice() { + boolean shouldAutoLaunchSingleChoice(TargetInfo target) { + final Intent intent = target.getResolvedIntent(); + final ResolveInfo resolve = target.getResolveInfo(); + + // When GET_CONTENT is handled by the DocumentsUI system component, + // we're okay automatically launching it, since it offers it's own + // intent disambiguation UI. + if (intent != null && Intent.ACTION_GET_CONTENT.equals(intent.getAction()) + && resolve != null && resolve.priority > 0 + && resolve.activityInfo != null && DocumentsContract.PACKAGE_DOCUMENTS_UI + .equals(resolve.activityInfo.packageName)) { + return true; + } + return false; } diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index ef9d1cebff57..17104894310e 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -796,7 +796,7 @@ public class ResolverActivity extends Activity { return false; } - boolean shouldAutoLaunchSingleChoice() { + boolean shouldAutoLaunchSingleChoice(TargetInfo target) { return true; } @@ -837,18 +837,21 @@ public class ResolverActivity extends Activity { mAlwaysUseOption = alwaysUseOption; int count = mAdapter.getUnfilteredCount(); - if ((!shouldAutoLaunchSingleChoice() && count > 0) - || count > 1 - || (count == 1 && mAdapter.getOtherProfile() != null)) { + if (count == 1 && mAdapter.getOtherProfile() == null) { + // Only one target, so we're a candidate to auto-launch! + final TargetInfo target = mAdapter.targetInfoForPosition(0, false); + if (shouldAutoLaunchSingleChoice(target)) { + safelyStartActivity(target); + mPackageMonitor.unregister(); + mRegistered = false; + finish(); + return true; + } + } + if (count > 0) { setContentView(layoutId); mAdapterView = (AbsListView) findViewById(R.id.resolver_list); onPrepareAdapterView(mAdapterView, mAdapter, alwaysUseOption); - } else if (count == 1) { - safelyStartActivity(mAdapter.targetInfoForPosition(0, false)); - mPackageMonitor.unregister(); - mRegistered = false; - finish(); - return true; } else { setContentView(R.layout.resolver_list); diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index b6240e48a1fd..c25db65b342b 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -46,6 +46,9 @@ public class MetricsLogger implements MetricsConstants { public static final int ACTION_FINGERPRINT_RENAME = 254; public static final int ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255; public static final int ACTION_WIGGLE_CAMERA_GESTURE = 256; + public static final int QS_LOCK_TILE = 257; + public static final int QS_USER_TILE = 258; + public static final int QS_BATTERY_TILE = 259; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index e39bf607e53e..64b7768c8337 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -105,7 +105,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 131 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 132 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -5704,6 +5704,8 @@ public final class BatteryStatsImpl extends BatteryStats { cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in); } } + } else { + mCpuClusterSpeed[cluster] = null; } } } else { @@ -9382,13 +9384,14 @@ public final class BatteryStatsImpl extends BatteryStats { u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][]; for (int cluster = 0; cluster < numClusters; cluster++) { - int NSB = in.readInt(); - if (mPowerProfile != null && - mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) { - throw new ParcelFormatException("File corrupt: too many speed bins " + NSB); - } - if (in.readInt() != 0) { + final int NSB = in.readInt(); + if (mPowerProfile != null && + mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) { + throw new ParcelFormatException("File corrupt: too many speed bins " + + NSB); + } + u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[NSB]; for (int speed = 0; speed < NSB; speed++) { if (in.readInt() != 0) { @@ -9397,6 +9400,8 @@ public final class BatteryStatsImpl extends BatteryStats { u.mCpuClusterSpeed[cluster][speed].readSummaryFromParcelLocked(in); } } + } else { + u.mCpuClusterSpeed[cluster] = null; } } } else { diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java index db2b41f52b8c..13d046e45070 100644 --- a/core/java/com/android/internal/os/InstallerConnection.java +++ b/core/java/com/android/internal/os/InstallerConnection.java @@ -20,6 +20,7 @@ import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.SystemClock; import android.util.Slog; + import libcore.io.IoUtils; import libcore.io.Streams; @@ -91,32 +92,29 @@ public class InstallerConnection { } } - public int dexopt(String apkPath, int uid, boolean isPublic, - String instructionSet, int dexoptNeeded, boolean bootComplete) { - return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded, - false, false, null, bootComplete); + public int dexopt(String apkPath, int uid, String instructionSet, + int dexoptNeeded, int dexFlags) { + return dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, + null /*outputPath*/, dexFlags); } - public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, - String instructionSet, int dexoptNeeded, boolean vmSafeMode, - boolean debuggable, String outputPath, boolean bootComplete) { + public int dexopt(String apkPath, int uid, String pkgName, String instructionSet, + int dexoptNeeded, String outputPath, int dexFlags) { StringBuilder builder = new StringBuilder("dexopt"); builder.append(' '); builder.append(apkPath); builder.append(' '); builder.append(uid); - builder.append(isPublic ? " 1" : " 0"); builder.append(' '); builder.append(pkgName); builder.append(' '); builder.append(instructionSet); builder.append(' '); builder.append(dexoptNeeded); - builder.append(vmSafeMode ? " 1" : " 0"); - builder.append(debuggable ? " 1" : " 0"); builder.append(' '); builder.append(outputPath != null ? outputPath : "!"); - builder.append(bootComplete ? " 1" : " 0"); + builder.append(' '); + builder.append(dexFlags); return execute(builder.toString()); } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index eee8b0812ea0..aaa89df1905d 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -486,8 +486,8 @@ public class ZygoteInit { final int dexoptNeeded = DexFile.getDexOptNeeded( classPathElement, "*", instructionSet, false /* defer */); if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { - installer.dexopt(classPathElement, Process.SYSTEM_UID, false, - instructionSet, dexoptNeeded, false /* boot complete */); + installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet, + dexoptNeeded, 0 /*dexFlags*/); } } } catch (IOException ioe) { diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java new file mode 100644 index 000000000000..4f17c39ddf81 --- /dev/null +++ b/core/java/com/android/internal/policy/DecorContext.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.policy; + +import android.content.Context; +import android.view.ContextThemeWrapper; +import android.view.WindowManager; +import android.view.WindowManagerImpl; + +/** + * Context for decor views which can be seeded with pure application context and not depend on the + * activity, but still provide some of the facilities that Activity has, e.g. themes. + * + * @hide + */ +class DecorContext extends ContextThemeWrapper { + private PhoneWindow mPhoneWindow; + private WindowManager mWindowManager; + + public DecorContext(Context context) { + super(context, null); + } + + void setPhoneWindow(PhoneWindow phoneWindow) { + mPhoneWindow = phoneWindow; + mWindowManager = null; + } + + @Override + public Object getSystemService(String name) { + if (Context.WINDOW_SERVICE.equals(name)) { + if (mWindowManager == null) { + WindowManagerImpl wm = + (WindowManagerImpl) super.getSystemService(Context.WINDOW_SERVICE); + mWindowManager = wm.createLocalWindowManager(mPhoneWindow); + } + return mWindowManager; + } + return super.getSystemService(name); + } +} diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index ec414474de70..b6d736465e17 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -32,6 +32,8 @@ import android.animation.Animator; import android.animation.ObjectAnimator; import android.app.ActivityManagerNative; import android.app.SearchManager; +import android.content.ContextWrapper; +import android.content.res.Resources; import android.os.Build; import android.os.UserHandle; @@ -71,6 +73,7 @@ import com.android.internal.view.menu.IconMenuPresenter; import com.android.internal.view.menu.ListMenuPresenter; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuDialogHelper; +import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.MenuPresenter; import com.android.internal.view.menu.MenuView; import com.android.internal.widget.ActionBarContextView; @@ -274,6 +277,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private ContextMenuBuilder mContextMenu; private MenuDialogHelper mContextMenuHelper; + private MenuPopupHelper mContextMenuPopupHelper; private boolean mClosingActionMenu; private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; @@ -315,6 +319,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private Rect mOutsets = new Rect(); private boolean mIsStartingWindow; + private int mTheme = -1; static class WindowManagerHolder { static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface( @@ -335,6 +340,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mElevation = preservedWindow.getElevation(); mLoadEleveation = false; mForceDecorInstall = true; + // If we're preserving window, carry over the app token from the preserved + // window, as we'll be skipping the addView in handleResumeActivity(), and + // the token will not be updated as for a new window. + getAttributes().token = preservedWindow.getAttributes().token; } } @@ -1123,6 +1132,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mContextMenuHelper.dismiss(); mContextMenuHelper = null; } + if (mContextMenuPopupHelper != null) { + mContextMenuPopupHelper.dismiss(); + mContextMenuPopupHelper = null; + } } @Override @@ -2850,6 +2863,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override + public boolean showContextMenuForChild(View originalView, float x, float y) { + // Reuse the context menu builder + if (mWindow.mContextMenu == null) { + mWindow.mContextMenu = new ContextMenuBuilder(getContext()); + mWindow.mContextMenu.setCallback(mWindow.mContextMenuCallback); + } else { + mWindow.mContextMenu.clearAll(); + } + + final MenuPopupHelper helper = mWindow.mContextMenu.showPopup( + getContext(), originalView, x, y); + if (helper != null) { + helper.setCallback(mWindow.mContextMenuCallback); + } else if (mWindow.mContextMenuPopupHelper != null) { + // No menu to show, but if we have a menu currently showing it just became blank. + // Close it. + mWindow.mContextMenuPopupHelper.dismiss(); + } + mWindow.mContextMenuPopupHelper = helper; + return helper != null; + } + + @Override public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY); @@ -3674,6 +3710,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { void setWindow(PhoneWindow phoneWindow) { mWindow = phoneWindow; + Context context = getContext(); + if (context instanceof DecorContext) { + DecorContext decorContex = (DecorContext) context; + decorContex.setPhoneWindow(mWindow); + } } /** @@ -3789,9 +3830,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // System process doesn't have application context and in that case we need to directly use // the context we have. Otherwise we want the application context, so we don't cling to the // activity. - Context context = getContext().getApplicationContext(); - if (context == null) { + Context applicationContext = getContext().getApplicationContext(); + Context context; + if (applicationContext == null) { context = getContext(); + } else { + context = new DecorContext(applicationContext); + if (mTheme != -1) { + context.setTheme(mTheme); + } } return new DecorView(context, featureId); } @@ -4162,14 +4209,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Dependent on the brightness of the used title we either use the // dark or the light button frame. if (nonClientDecorView == null) { + Context context = mDecor.getContext(); TypedValue value = new TypedValue(); - getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true); - // We can't use the application context inside the general inflater, because some - // views might depend on the fact that they get Activity or even specific activity. - // We control the NonClientDecor, so we know that application context should be - // safe enough. - LayoutInflater inflater = - mLayoutInflater.cloneInContext(getContext().getApplicationContext()); + context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true); + LayoutInflater inflater = mLayoutInflater.from(context); if (Color.luminance(value.data) < 0.5) { nonClientDecorView = (NonClientDecorView) inflater.inflate( R.layout.non_client_decor_dark, null); @@ -4202,8 +4245,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) { mDecor.postOnAnimation(mInvalidatePanelMenuRunnable); } + } else { + mDecor.setWindow(this); } - mDecor.setWindow(this); if (mContentParent == null) { mContentParent = generateLayout(mDecor); @@ -5377,4 +5421,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public boolean hasNonClientDecorView() { return mNonClientDecorView != null; } + + @Override + public void setTheme(int resid) { + mTheme = resid; + if (mDecor != null) { + Context context = mDecor.getContext(); + if (context instanceof DecorContext) { + context.setTheme(resid); + } + } + } } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index ab3ec985d688..11ef18b4d5c0 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -74,7 +74,9 @@ oneway interface IStatusBar /** * Notifies the status bar that a camera launch gesture has been detected. + * + * @param source the identifier for the gesture, see {@link StatusBarManager} */ - void onCameraLaunchGestureDetected(); + void onCameraLaunchGestureDetected(int source); } diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index 44df0ce89133..b44baa2b8422 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -35,7 +35,7 @@ import java.util.Arrays; public class FloatingActionMode extends ActionMode { private static final int MAX_HIDE_DURATION = 3000; - private static final int MOVING_HIDE_DELAY = 300; + private static final int MOVING_HIDE_DELAY = 50; private final Context mContext; private final ActionMode.Callback2 mCallback; @@ -181,7 +181,6 @@ public class FloatingActionMode extends ActionMode { // Content rect is moving. mOriginatingView.removeCallbacks(mMovingOff); mFloatingToolbarVisibilityHelper.setMoving(true); - mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY); mFloatingToolbar.setContentRect(mContentRectOnScreen); @@ -189,9 +188,9 @@ public class FloatingActionMode extends ActionMode { } } else { mFloatingToolbarVisibilityHelper.setOutOfBounds(true); - mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mContentRectOnScreen.setEmpty(); } + mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mPreviousContentRectOnScreen.set(mContentRectOnScreen); } diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java index 415f32528914..293e2ade7229 100644 --- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java +++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java @@ -20,14 +20,16 @@ import android.view.ViewTreeObserver; import android.view.View.OnAttachStateChangeListener; import android.view.View.OnKeyListener; import android.view.ViewTreeObserver.OnGlobalLayoutListener; -import android.widget.AdapterView; import android.widget.DropDownListView; +import android.widget.FrameLayout; import android.widget.MenuItemHoverListener; +import android.widget.ListAdapter; import android.widget.ListView; import android.widget.MenuPopupWindow; import android.widget.MenuPopupWindow.MenuDropDownListView; import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; +import android.widget.TextView; import com.android.internal.util.Preconditions; @@ -36,8 +38,8 @@ import com.android.internal.util.Preconditions; * side. * @hide */ -final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemClickListener, - MenuPresenter, OnKeyListener, PopupWindow.OnDismissListener { +final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKeyListener, + PopupWindow.OnDismissListener { @Retention(RetentionPolicy.SOURCE) @IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT}) public @interface HorizPosition {} @@ -96,7 +98,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl int menuIndex = -1; for (int i = 0; i < mListViews.size(); i++) { final MenuDropDownListView view = (MenuDropDownListView) mListViews.get(i); - final MenuAdapter adapter = (MenuAdapter) view.getAdapter(); + final MenuAdapter adapter = toMenuAdapter(view.getAdapter()); if (adapter.getAdapterMenu() == menu) { menuIndex = i; @@ -129,7 +131,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl int nextIndex = mListViews.indexOf(view) + 1; if (nextIndex < mListViews.size()) { MenuAdapter nextSubMenuAdapter = - (MenuAdapter) mListViews.get(nextIndex).getAdapter(); + toMenuAdapter(mListViews.get(nextIndex).getAdapter()); // Disable exit animation, to prevent overlapping fading out // submenus. mPopupWindows.get(nextIndex).setExitTransition(null); @@ -151,9 +153,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl final MenuDropDownListView nextView = (MenuDropDownListView) mListViews.get(menuIndex + 1); - final MenuAdapter nextAdapter = (MenuAdapter) nextView.getAdapter(); - - view.clearSelection(); + final MenuAdapter nextAdapter = toMenuAdapter(nextView.getAdapter()); mSubMenuHoverHandler.removeCallbacksAndMessages(null); mSubMenuHoverHandler.postDelayed(new Runnable() { @@ -162,9 +162,14 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl // Make sure the menu wasn't already closed by something else and that // it wasn't re-hovered by the user since this was scheduled. int nextMenuIndex = mListViews.indexOf(nextView); + if (nextMenuIndex != -1 && nextView.getSelectedView() == null) { // Disable exit animation, to prevent overlapping fading out submenus. - mPopupWindows.get(nextMenuIndex).setExitTransition(null); + for (int i = nextMenuIndex; i < mPopupWindows.size(); i++) { + final MenuPopupWindow popupWindow = mPopupWindows.get(i); + popupWindow.setExitTransition(null); + popupWindow.setAnimationStyle(0); + } nextAdapter.getAdapterMenu().close(); } } @@ -178,9 +183,13 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl private View mShownAnchorView; private List<DropDownListView> mListViews; private List<MenuPopupWindow> mPopupWindows; + private int mLastPosition; + private List<Integer> mPositions; private List<int[]> mOffsets; - private int mPreferredPosition; + private int mInitXOffset; + private int mInitYOffset; private boolean mForceShowIcon; + private boolean mShowTitle; private Callback mPresenterCallback; private ViewTreeObserver mTreeObserver; private PopupWindow.OnDismissListener mOnDismissListener; @@ -203,14 +212,14 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl final Resources res = context.getResources(); final Configuration config = res.getConfiguration(); mLayoutDirection = config.getLayoutDirection(); - mPreferredPosition = mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT : - HORIZ_POSITION_RIGHT; + mLastPosition = getInitialMenuPosition(); mMenuMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2, res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth)); mPopupWindows = new ArrayList<MenuPopupWindow>(); mListViews = new ArrayList<DropDownListView>(); mOffsets = new ArrayList<int[]>(); + mPositions = new ArrayList<Integer>(); mSubMenuHoverHandler = new Handler(); } @@ -244,7 +253,25 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl for (int i = 0; i < mPopupWindows.size(); i++) { MenuPopupWindow popupWindow = mPopupWindows.get(i); popupWindow.show(); - mListViews.add((DropDownListView) popupWindow.getListView()); + DropDownListView listView = (DropDownListView) popupWindow.getListView(); + mListViews.add(listView); + + MenuBuilder menu = toMenuAdapter(listView.getAdapter()).getAdapterMenu(); + if (i == 0 && mShowTitle && menu.getHeaderTitle() != null) { + FrameLayout titleItemView = + (FrameLayout) LayoutInflater.from(mContext).inflate( + com.android.internal.R.layout.popup_menu_header_item_layout, + listView, + false); + TextView titleView = (TextView) titleItemView.findViewById( + com.android.internal.R.id.title); + titleView.setText(menu.getHeaderTitle()); + titleItemView.setEnabled(false); + listView.addHeaderView(titleItemView, null, false); + + // Update to show the title. + popupWindow.show(); + } } mShownAnchorView = mAnchorView; @@ -271,12 +298,6 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - MenuAdapter adapter = (MenuAdapter) parent.getAdapter(); - adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); - } - - @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { dismiss(); @@ -286,6 +307,16 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl } /** + * Determines the proper initial menu position for the current LTR/RTL configuration. + * @return The initial position. + */ + @HorizPosition + private int getInitialMenuPosition() { + return mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT : + HORIZ_POSITION_RIGHT; + } + + /** * Determines whether the next submenu (of the given width) should display on the right or on * the left of the most recent menu. * @@ -302,7 +333,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl final Rect displayFrame = new Rect(); mShownAnchorView.getWindowVisibleDisplayFrame(displayFrame); - if (mPreferredPosition == HORIZ_POSITION_RIGHT) { + if (mLastPosition == HORIZ_POSITION_RIGHT) { final int right = screenLocation[0] + lastListView.getWidth() + nextMenuWidth; if (right > displayFrame.right) { return HORIZ_POSITION_LEFT; @@ -342,7 +373,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl ListView lastListView = mListViews.get(mListViews.size() - 1); @HorizPosition int nextMenuPosition = getNextMenuPosition(menuWidth); boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT; - mPreferredPosition = nextMenuPosition; + mLastPosition = nextMenuPosition; int[] lastLocation = new int[2]; lastListView.getLocationOnScreen(lastLocation); @@ -367,6 +398,9 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl y = lastOffset[1] + lastListView.getSelectedView().getTop() - lastListView.getChildAt(0).getTop(); + } else { + x = mInitXOffset; + y = mInitYOffset; } popupWindow.setWidth(menuWidth); @@ -379,11 +413,13 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl // we deliberately do not yet show the popupWindow, as #show() will do that later. if (isShowing()) { popupWindow.show(); - mListViews.add((DropDownListView) popupWindow.getListView()); + DropDownListView listView = (DropDownListView) popupWindow.getListView(); + mListViews.add(listView); } int[] offsets = {x, y}; mOffsets.add(offsets); + mPositions.add(mLastPosition); } /** @@ -410,8 +446,9 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl if (dismissedIndex != -1) { for (int i = dismissedIndex; i < mListViews.size(); i++) { ListView view = mListViews.get(i); - MenuAdapter adapter = (MenuAdapter) view.getAdapter(); - adapter.mAdapterMenu.close(); + ListAdapter adapter = view.getAdapter(); + MenuAdapter menuAdapter = toMenuAdapter(adapter); + menuAdapter.mAdapterMenu.close(); } } } @@ -419,7 +456,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl @Override public void updateMenuView(boolean cleared) { for (ListView view : mListViews) { - ((MenuAdapter) view.getAdapter()).notifyDataSetChanged(); + toMenuAdapter(view.getAdapter()).notifyDataSetChanged(); } } @@ -432,7 +469,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl public boolean onSubMenuSelected(SubMenuBuilder subMenu) { // Don't allow double-opening of the same submenu. for (ListView view : mListViews) { - if (((MenuAdapter) view.getAdapter()).mAdapterMenu.equals(subMenu)) { + if (toMenuAdapter(view.getAdapter()).mAdapterMenu.equals(subMenu)) { // Just re-focus that one. view.requestFocus(); return true; @@ -456,7 +493,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl for (int i = 0; i < mListViews.size(); i++) { ListView view = mListViews.get(i); - MenuAdapter adapter = (MenuAdapter) view.getAdapter(); + MenuAdapter adapter = toMenuAdapter(view.getAdapter()); if (menuIndex == -1 && menu == adapter.mAdapterMenu) { menuIndex = i; @@ -479,9 +516,11 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl mListViews.subList(menuIndex, mListViews.size()).clear(); mOffsets.subList(menuIndex, mOffsets.size()).clear(); - // If there's still a menu open, refocus the new leaf [sub]menu. - if (mListViews.size() > 0) { - mListViews.get(mListViews.size() - 1).requestFocus(); + mPositions.subList(menuIndex, mPositions.size()).clear(); + if (mPositions.size() > 0) { + mLastPosition = mPositions.get(mPositions.size() - 1); + } else { + mLastPosition = getInitialMenuPosition(); } } @@ -540,4 +579,18 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl return mListViews.size() > 0 ? mListViews.get(mListViews.size() - 1) : null; } + @Override + public void setHorizontalOffset(int x) { + mInitXOffset = x; + } + + @Override + public void setVerticalOffset(int y) { + mInitYOffset = y; + } + + @Override + public void setShowTitle(boolean showTitle) { + mShowTitle = showTitle; + } }
\ No newline at end of file diff --git a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java index bf44d51b6dd9..aaa1bf16bf80 100644 --- a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java +++ b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java @@ -17,6 +17,7 @@ package com.android.internal.view.menu; import android.content.Context; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.IBinder; import android.util.EventLog; @@ -93,4 +94,29 @@ public class ContextMenuBuilder extends MenuBuilder implements ContextMenu { return null; } + public MenuPopupHelper showPopup(Context context, View originalView, float x, float y) { + if (originalView != null) { + // Let relevant views and their populate context listeners populate + // the context menu + originalView.createContextMenu(this); + } + + if (getVisibleItems().size() > 0) { + EventLog.writeEvent(50001, 1); + + int location[] = new int[2]; + originalView.getLocationOnScreen(location); + + final MenuPopupHelper helper = new MenuPopupHelper( + context, + this, + originalView, + false /* overflowOnly */, + com.android.internal.R.attr.contextPopupMenuStyle); + helper.show(Math.round(x), Math.round(y)); + return helper; + } + + return null; + } } diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java index b43e8adbc8ac..98f5d9061e14 100644 --- a/core/java/com/android/internal/view/menu/MenuPopup.java +++ b/core/java/com/android/internal/view/menu/MenuPopup.java @@ -17,10 +17,13 @@ package com.android.internal.view.menu; import android.content.Context; +import android.view.MenuItem; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.FrameLayout; +import android.widget.HeaderViewListAdapter; import android.widget.ListAdapter; import android.widget.PopupWindow; @@ -30,7 +33,8 @@ import android.widget.PopupWindow; * * @hide */ -public abstract class MenuPopup implements ShowableListMenu, MenuPresenter { +public abstract class MenuPopup implements ShowableListMenu, MenuPresenter, + AdapterView.OnItemClickListener { public abstract void setForceShowIcon(boolean forceShow); @@ -49,6 +53,18 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter { public abstract void setAnchorView(View anchor); + public abstract void setHorizontalOffset(int x); + + public abstract void setVerticalOffset(int y); + + /** + * Set whether a title entry should be shown in the popup menu (if a title exists for the + * menu). + * + * @param showTitle + */ + public abstract void setShowTitle(boolean showTitle); + /** * Set a listener to receive a callback when the popup is dismissed. * @@ -81,6 +97,16 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter { return 0; } + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + ListAdapter outerAdapter = (ListAdapter) parent.getAdapter(); + MenuAdapter wrappedAdapter = toMenuAdapter(outerAdapter); + + // Use the position from the outer adapter so that if a header view was added, we don't get + // an off-by-1 error in position. + wrappedAdapter.mAdapterMenu.performItemAction((MenuItem) outerAdapter.getItem(position), 0); + } + /** * Measures the width of the given menu view. * @@ -121,4 +147,19 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter { return maxWidth; } -}
\ No newline at end of file + + /** + * Converts the given ListAdapter originating from a menu, to a MenuAdapter, accounting for + * the possibility of the parameter adapter actually wrapping the MenuAdapter. (That could + * happen if a header view was added on the menu.) + * + * @param adapter + * @return + */ + protected static MenuAdapter toMenuAdapter(ListAdapter adapter) { + if (adapter instanceof HeaderViewListAdapter) { + return (MenuAdapter) ((HeaderViewListAdapter) adapter).getWrappedAdapter(); + } + return (MenuAdapter) adapter; + } +} diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index ea7998339f3b..e674eccd889d 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -39,7 +39,11 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { private MenuPopup mPopup; private int mDropDownGravity = Gravity.NO_GRAVITY; + private boolean mForceShowIcon; + private boolean mShowTitle; private Callback mPresenterCallback; + private int mInitXOffset; + private int mInitYOffset; public MenuPopupHelper(Context context, MenuBuilder menu) { this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0); @@ -81,6 +85,7 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { } public void setForceShowIcon(boolean forceShow) { + mForceShowIcon = forceShow; mPopup.setForceShowIcon(forceShow); } @@ -99,6 +104,12 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { } } + public void show(int x, int y) { + if (!tryShow(x, y)) { + throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); + } + } + public ShowableListMenu getPopup() { return mPopup; } @@ -118,10 +129,40 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { return false; } + mInitXOffset = 0; + mInitYOffset = 0; + mShowTitle = false; + + showPopup(); + return true; + } + + public boolean tryShow(int x, int y) { + if (isShowing()) { + return true; + } + + if (mAnchorView == null) { + return false; + } + + mInitXOffset = x; + mInitYOffset = y; + mShowTitle = true; + + showPopup(); + return true; + } + + private void showPopup() { mPopup = createMenuPopup(); mPopup.setAnchorView(mAnchorView); - mPopup.setGravity(mDropDownGravity); mPopup.setCallback(mPresenterCallback); + mPopup.setForceShowIcon(mForceShowIcon); + mPopup.setGravity(mDropDownGravity); + mPopup.setHorizontalOffset(mInitXOffset); + mPopup.setShowTitle(mShowTitle); + mPopup.setVerticalOffset(mInitYOffset); // In order for subclasses of MenuPopupHelper to satisfy the OnDismissedListener interface, // we must set the listener to this outer Helper rather than to the inner MenuPopup. @@ -131,7 +172,6 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { mPopup.addMenu(mMenu); mPopup.show(); - return true; } public void dismiss() { @@ -149,7 +189,6 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { return mPopup != null && mPopup.isShowing(); } - public void setCallback(MenuPresenter.Callback cb) { mPresenterCallback = cb; mPopup.setCallback(cb); diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java index 8877f3d96a39..caee0d2d9a74 100644 --- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java +++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java @@ -6,17 +6,17 @@ import android.os.Parcelable; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.View.OnAttachStateChangeListener; import android.view.View.OnKeyListener; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.ViewTreeObserver; -import android.widget.AdapterView; +import android.widget.FrameLayout; import android.widget.ListView; import android.widget.MenuPopupWindow; import android.widget.PopupWindow; +import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import android.widget.PopupWindow.OnDismissListener; @@ -92,6 +92,10 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On private int mDropDownGravity = Gravity.NO_GRAVITY; + private int mXOffset; + private int mYOffset; + private boolean mShowTitle; + public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr, int popupStyleRes, boolean overflowOnly) { mContext = Preconditions.checkNotNull(context); @@ -158,8 +162,28 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On mPopup.setContentWidth(mContentWidth); mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); + mPopup.setHorizontalOffset(mXOffset); + mPopup.setVerticalOffset(mYOffset); mPopup.show(); - mPopup.getListView().setOnKeyListener(this); + + ListView listView = mPopup.getListView(); + listView.setOnKeyListener(this); + + if (mShowTitle && mMenu.getHeaderTitle() != null) { + FrameLayout titleItemView = + (FrameLayout) LayoutInflater.from(mContext).inflate( + com.android.internal.R.layout.popup_menu_header_item_layout, + listView, + false); + TextView titleView = (TextView) titleItemView.findViewById( + com.android.internal.R.id.title); + titleView.setText(mMenu.getHeaderTitle()); + titleItemView.setEnabled(false); + listView.addHeaderView(titleItemView, null, false); + + // Update to show the title. + mPopup.show(); + } return true; } @@ -178,12 +202,6 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - MenuAdapter adapter = mAdapter; - adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); - } - - @Override public void addMenu(MenuBuilder menu) { // No-op: standard implementation has only one menu which is set in the constructor. } @@ -288,4 +306,20 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On public ListView getListView() { return mPopup.getListView(); } -}
\ No newline at end of file + + + @Override + public void setHorizontalOffset(int x) { + mXOffset = x; + } + + @Override + public void setVerticalOffset(int y) { + mYOffset = y; + } + + @Override + public void setShowTitle(boolean showTitle) { + mShowTitle = showTitle; + } +} diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index ca6fe619f528..7bab446d4705 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -73,6 +73,8 @@ public final class FloatingToolbar { // This class is responsible for the public API of the floating toolbar. // It delegates rendering operations to the FloatingToolbarPopup. + public static final String FLOATING_TOOLBAR_TAG = "floating_toolbar"; + private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER = new MenuItem.OnMenuItemClickListener() { @Override @@ -1460,8 +1462,10 @@ public final class FloatingToolbar { } private static ViewGroup createContentContainer(Context context) { - return (ViewGroup) LayoutInflater.from(context) + ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context) .inflate(R.layout.floating_popup_container, null); + contentContainer.setTag(FLOATING_TOOLBAR_TAG); + return contentContainer; } private static PopupWindow createPopupWindow(View content) { @@ -1488,10 +1492,9 @@ public final class FloatingToolbar { private static AnimatorSet createEnterAnimation(View view) { AnimatorSet animation = new AnimatorSet(); animation.playTogether( - ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(200), + ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150), // Make sure that view.x is always fixed throughout the duration of this animation. ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX())); - animation.setStartDelay(50); return animation; } @@ -1506,7 +1509,7 @@ public final class FloatingToolbar { View view, int startDelay, Animator.AnimatorListener listener) { AnimatorSet animation = new AnimatorSet(); animation.playTogether( - ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(200)); + ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100)); animation.setStartDelay(startDelay); animation.addListener(listener); return animation; diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index f7e9add58f21..60ef4a47b230 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -1078,7 +1078,7 @@ public class LockPatternUtils { long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId); final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId); final long now = SystemClock.elapsedRealtime(); - if (deadline < now) { + if (deadline < now && deadline != 0) { // timeout expired setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId); setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId); diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java index 6ab306cec730..56cf9216d0c9 100644 --- a/core/java/com/android/internal/widget/NonClientDecorView.java +++ b/core/java/com/android/internal/widget/NonClientDecorView.java @@ -57,7 +57,8 @@ import com.android.internal.policy.PhoneWindow; * </ul> * This will be mitigated once b/22527834 will be addressed. */ -public class NonClientDecorView extends LinearLayout implements View.OnClickListener { +public class NonClientDecorView extends LinearLayout + implements View.OnClickListener, View.OnTouchListener { private final static String TAG = "NonClientDecorView"; // The height of a window which has focus in DIP. private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20; @@ -112,7 +113,7 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList } @Override - public boolean onTouchEvent(MotionEvent e) { + public boolean onTouch(View v, MotionEvent e) { // Note: There are no mixed events. When a new device gets used (e.g. 1. Mouse, 2. touch) // the old input device events get cancelled first. So no need to remember the kind of // input device we are listening to. @@ -224,6 +225,7 @@ public class NonClientDecorView extends LinearLayout implements View.OnClickList boolean invisible = isFillingScreen() || !mShowDecor; View caption = getChildAt(0); caption.setVisibility(invisible ? GONE : VISIBLE); + caption.setOnTouchListener(this); mVisible = !invisible; } diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 75da27e25abb..20d00b03092a 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -1,6 +1,5 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL @@ -259,6 +258,9 @@ LOCAL_SHARED_LIBRARIES += \ # <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp LOCAL_C_INCLUDES += bionic/libc/private +# AndroidRuntime.h depends on nativehelper/jni.h +LOCAL_EXPORT_C_INCLUDE_DIRS := libnativehelper/include + LOCAL_MODULE:= libandroid_runtime # -Wno-unknown-pragmas: necessary for Clang as the GL bindings need to turn diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index e4bc80013b9c..ffc69a93f106 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -217,7 +217,7 @@ static void com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup(JNIE /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeFinishInit", "()V", (void*) com_android_internal_os_RuntimeInit_nativeFinishInit }, { "nativeZygoteInit", "()V", diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index fbe3ececc348..e6c7c2bcf9d7 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -1348,7 +1348,7 @@ static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) { /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gBitmapMethods[] = { +static const JNINativeMethod gBitmapMethods[] = { { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", (void*)Bitmap_creator }, { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 20a54e538ea8..28bc7fe47dd2 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -542,7 +542,7 @@ jobject decodeBitmap(JNIEnv* env, void* data, size_t size) { /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeDecodeStream", "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", (void*)nativeDecodeStream @@ -569,7 +569,7 @@ static JNINativeMethod gMethods[] = { }, }; -static JNINativeMethod gOptionsMethods[] = { +static const JNINativeMethod gOptionsMethods[] = { { "requestCancel", "()V", (void*)nativeRequestCancel } }; diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index 1bbbb08990ce..2df3a4641aeb 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -261,7 +261,7 @@ static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) { /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gBitmapRegionDecoderMethods[] = { +static const JNINativeMethod gBitmapRegionDecoderMethods[] = { { "nativeDecodeRegion", "(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", (void*)nativeDecodeRegion}, diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp index 036ece1cec28..6fcf6892d490 100644 --- a/core/jni/android/graphics/Camera.cpp +++ b/core/jni/android/graphics/Camera.cpp @@ -115,7 +115,7 @@ static jfloat Camera_dotWithNormal(JNIEnv* env, jobject obj, /* * JNI registration. */ -static JNINativeMethod gCameraMethods[] = { +static const JNINativeMethod gCameraMethods[] = { /* name, signature, funcPtr */ { "nativeConstructor", "()V", (void*)Camera_constructor }, diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp index deb4971a8a01..728bc1c3677e 100644 --- a/core/jni/android/graphics/CanvasProperty.cpp +++ b/core/jni/android/graphics/CanvasProperty.cpp @@ -39,7 +39,7 @@ static jlong createPaint(JNIEnv* env, jobject clazz, jlong paintPtr) { // JNI Glue // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreateFloat", "(F)J", (void*) createFloat }, { "nCreatePaint", "(J)J", (void*) createPaint }, }; diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp index d03bcf0fe3ac..83fd07382fe0 100644 --- a/core/jni/android/graphics/ColorFilter.cpp +++ b/core/jni/android/graphics/ColorFilter.cpp @@ -57,19 +57,19 @@ public: } }; -static JNINativeMethod colorfilter_methods[] = { +static const JNINativeMethod colorfilter_methods[] = { {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer} }; -static JNINativeMethod porterduff_methods[] = { +static const JNINativeMethod porterduff_methods[] = { { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter }, }; -static JNINativeMethod lighting_methods[] = { +static const JNINativeMethod lighting_methods[] = { { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter }, }; -static JNINativeMethod colormatrix_methods[] = { +static const JNINativeMethod colormatrix_methods[] = { { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter }, }; diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp index 90ef6c0745cd..c1dc0dd025b6 100644 --- a/core/jni/android/graphics/DrawFilter.cpp +++ b/core/jni/android/graphics/DrawFilter.cpp @@ -97,11 +97,11 @@ public: } }; -static JNINativeMethod drawfilter_methods[] = { +static const JNINativeMethod drawfilter_methods[] = { {"nativeDestructor", "(J)V", (void*) SkDrawFilterGlue::finalizer} }; -static JNINativeMethod paintflags_methods[] = { +static const JNINativeMethod paintflags_methods[] = { {"nativeConstructor","(II)J", (void*) SkDrawFilterGlue::CreatePaintFlagsDF} }; diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index 38db76b0b183..dac6d96eb7df 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -124,7 +124,7 @@ static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPt /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gFontFamilyMethods[] = { +static const JNINativeMethod gFontFamilyMethods[] = { { "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create }, { "nUnrefFamily", "(J)V", (void*)FontFamily_unref }, { "nAddFont", "(JLjava/lang/String;)Z", (void*)FontFamily_addFont }, diff --git a/core/jni/android/graphics/Interpolator.cpp b/core/jni/android/graphics/Interpolator.cpp index 3593d1a4ab32..fa28359281db 100644 --- a/core/jni/android/graphics/Interpolator.cpp +++ b/core/jni/android/graphics/Interpolator.cpp @@ -71,7 +71,7 @@ static jint Interpolator_timeToValues(JNIEnv* env, jobject clazz, jlong interpHa /* * JNI registration. */ -static JNINativeMethod gInterpolatorMethods[] = { +static const JNINativeMethod gInterpolatorMethods[] = { { "nativeConstructor", "(II)J", (void*)Interpolator_constructor }, { "nativeDestructor", "(J)V", (void*)Interpolator_destructor }, { "nativeReset", "(JII)V", (void*)Interpolator_reset }, diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp index d65864312196..2b4a1abbd673 100644 --- a/core/jni/android/graphics/MaskFilter.cpp +++ b/core/jni/android/graphics/MaskFilter.cpp @@ -61,19 +61,19 @@ public: } }; -static JNINativeMethod gMaskFilterMethods[] = { +static const JNINativeMethod gMaskFilterMethods[] = { { "nativeDestructor", "(J)V", (void*)SkMaskFilterGlue::destructor } }; -static JNINativeMethod gBlurMaskFilterMethods[] = { +static const JNINativeMethod gBlurMaskFilterMethods[] = { { "nativeConstructor", "(FI)J", (void*)SkMaskFilterGlue::createBlur } }; -static JNINativeMethod gEmbossMaskFilterMethods[] = { +static const JNINativeMethod gEmbossMaskFilterMethods[] = { { "nativeConstructor", "([FFFF)J", (void*)SkMaskFilterGlue::createEmboss } }; -static JNINativeMethod gTableMaskFilterMethods[] = { +static const JNINativeMethod gTableMaskFilterMethods[] = { { "nativeNewTable", "([B)J", (void*)SkMaskFilterGlue::createTable }, { "nativeNewClip", "(II)J", (void*)SkMaskFilterGlue::createClipTable }, { "nativeNewGamma", "(F)J", (void*)SkMaskFilterGlue::createGammaTable } diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp index 101e2ba603e6..b0f3bb4b965a 100644 --- a/core/jni/android/graphics/Matrix.cpp +++ b/core/jni/android/graphics/Matrix.cpp @@ -302,7 +302,7 @@ public: } }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer}, {"native_create","(J)J", (void*) SkMatrixGlue::create}, diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp index d67ed10e9ef1..498c5902e5fd 100644 --- a/core/jni/android/graphics/Movie.cpp +++ b/core/jni/android/graphics/Movie.cpp @@ -135,7 +135,7 @@ static void movie_destructor(JNIEnv* env, jobject, jlong movieHandle) { ////////////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "width", "()I", (void*)movie_width }, { "height", "()I", (void*)movie_height }, { "isOpaque", "()Z", (void*)movie_isOpaque }, diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp index 1c282623f455..3ccbb35cc960 100644 --- a/core/jni/android/graphics/NinePatch.cpp +++ b/core/jni/android/graphics/NinePatch.cpp @@ -108,7 +108,7 @@ public: ///////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gNinePatchMethods[] = { +static const JNINativeMethod gNinePatchMethods[] = { { "isNinePatchChunk", "([B)Z", (void*) SkNinePatchGlue::isNinePatchChunk }, { "validateNinePatchChunk", "([B)J", (void*) SkNinePatchGlue::validateNinePatchChunk }, diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 988d13aa7ea8..223dae0404c5 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -44,6 +44,7 @@ #include "TypefaceImpl.h" #include <vector> +#include <memory> // temporary for debugging #include <Caches.h> @@ -569,137 +570,9 @@ public: return descent - ascent + leading; } - static jfloat measureText_CIII(JNIEnv* env, jobject jpaint, jcharArray text, jint index, jint count, - jint bidiFlags) { - NPE_CHECK_RETURN_ZERO(env, jpaint); - NPE_CHECK_RETURN_ZERO(env, text); - - size_t textLength = env->GetArrayLength(text); - if ((index | count) < 0 || (size_t)(index + count) > textLength) { - doThrowAIOOBE(env); - return 0; - } - if (count == 0) { - return 0; - } - - Paint* paint = getNativePaint(env, jpaint); - const jchar* textArray = env->GetCharArrayElements(text, NULL); - jfloat result = 0; - - Layout layout; - TypefaceImpl* typeface = getNativeTypeface(env, jpaint); - MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray + index, 0, count, - count); - result = layout.getAdvance(); - env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT); - return result; - } - - static jfloat measureText_StringIII(JNIEnv* env, jobject jpaint, jstring text, jint start, jint end, - jint bidiFlags) { - NPE_CHECK_RETURN_ZERO(env, jpaint); - NPE_CHECK_RETURN_ZERO(env, text); - - size_t textLength = env->GetStringLength(text); - int count = end - start; - if ((start | count) < 0 || (size_t)end > textLength) { - doThrowAIOOBE(env); - return 0; - } - if (count == 0) { - return 0; - } - - const jchar* textArray = env->GetStringChars(text, NULL); - Paint* paint = getNativePaint(env, jpaint); - jfloat width = 0; - - Layout layout; - TypefaceImpl* typeface = getNativeTypeface(env, jpaint); - // Only the substring is used for measurement, so no additional context is passed in. This - // behavior is consistent between char[] and String specializations. - MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray + start, 0, count, count); - width = layout.getAdvance(); - - env->ReleaseStringChars(text, textArray); - return width; - } - - static jfloat measureText_StringI(JNIEnv* env, jobject jpaint, jstring text, jint bidiFlags) { - NPE_CHECK_RETURN_ZERO(env, jpaint); - NPE_CHECK_RETURN_ZERO(env, text); - - size_t textLength = env->GetStringLength(text); - if (textLength == 0) { - return 0; - } - - const jchar* textArray = env->GetStringChars(text, NULL); - Paint* paint = getNativePaint(env, jpaint); - jfloat width = 0; - - Layout layout; - TypefaceImpl* typeface = getNativeTypeface(env, jpaint); - MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, 0, textLength, textLength); - width = layout.getAdvance(); - - env->ReleaseStringChars(text, textArray); - return width; - } - - static int dotextwidths(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar text[], int count, - jfloatArray widths, jint bidiFlags) { - NPE_CHECK_RETURN_ZERO(env, paint); - NPE_CHECK_RETURN_ZERO(env, text); - - if (count < 0 || !widths) { - doThrowAIOOBE(env); - return 0; - } - if (count == 0) { - return 0; - } - size_t widthsLength = env->GetArrayLength(widths); - if ((size_t)count > widthsLength) { - doThrowAIOOBE(env); - return 0; - } - - AutoJavaFloatArray autoWidths(env, widths, count); - jfloat* widthsArray = autoWidths.ptr(); - - Layout layout; - MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count); - layout.getAdvances(widthsArray); - - return count; - } - - static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text, - jint index, jint count, jint bidiFlags, jfloatArray widths) { - Paint* paint = reinterpret_cast<Paint*>(paintHandle); - TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); - const jchar* textArray = env->GetCharArrayElements(text, NULL); - count = dotextwidths(env, paint, typeface, textArray + index, count, widths, bidiFlags); - env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), - JNI_ABORT); - return count; - } - - static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring text, - jint start, jint end, jint bidiFlags, jfloatArray widths) { - Paint* paint = reinterpret_cast<Paint*>(paintHandle); - TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); - const jchar* textArray = env->GetStringChars(text, NULL); - int count = dotextwidths(env, paint, typeface, textArray + start, end - start, widths, bidiFlags); - env->ReleaseStringChars(text, textArray); - return count; - } - - static jfloat doTextRunAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface, const jchar *text, - jint start, jint count, jint contextCount, jboolean isRtl, - jfloatArray advances, jint advancesIndex) { + static jfloat doTextAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface, + const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags, + jfloatArray advances, jint advancesIndex) { NPE_CHECK_RETURN_ZERO(env, paint); NPE_CHECK_RETURN_ZERO(env, text); @@ -712,50 +585,45 @@ public: } if (advances) { size_t advancesLength = env->GetArrayLength(advances); - if ((size_t)count > advancesLength) { + if ((size_t)(count + advancesIndex) > advancesLength) { doThrowAIOOBE(env); return 0; } } - jfloat* advancesArray = new jfloat[count]; - jfloat totalAdvance = 0; - - int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; Layout layout; - MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount); - layout.getAdvances(advancesArray); - totalAdvance = layout.getAdvance(); - + MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, + contextCount); if (advances != NULL) { - env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray); + std::unique_ptr<jfloat> advancesArray(new jfloat[count]); + layout.getAdvances(advancesArray.get()); + env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get()); } - delete [] advancesArray; - return totalAdvance; + return layout.getAdvance(); } - static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle, + static jfloat getTextAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text, jint index, jint count, jint contextIndex, jint contextCount, - jboolean isRtl, jfloatArray advances, jint advancesIndex) { + jint bidiFlags, jfloatArray advances, jint advancesIndex) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); jchar* textArray = env->GetCharArrayElements(text, NULL); - jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex, - index - contextIndex, count, contextCount, isRtl, advances, advancesIndex); + jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex, + index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); return result; } - static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle, + static jfloat getTextAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, - jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl, + jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint bidiFlags, jfloatArray advances, jint advancesIndex) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); const jchar* textArray = env->GetStringChars(text, NULL); - jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart, - start - contextStart, end - start, contextEnd - contextStart, isRtl, + jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart, + start - contextStart, end - start, contextEnd - contextStart, bidiFlags, advances, advancesIndex); env->ReleaseStringChars(text, textArray); return result; @@ -1095,7 +963,7 @@ public: }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"finalizer", "(J)V", (void*) PaintGlue::finalizer}, {"native_init","()J", (void*) PaintGlue::init}, {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint}, @@ -1160,18 +1028,13 @@ static JNINativeMethod methods[] = { (void*)PaintGlue::getFontMetrics}, {"getFontMetricsInt", "!(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt}, - {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII}, - {"native_measureText","(Ljava/lang/String;I)F", (void*) PaintGlue::measureText_StringI}, - {"native_measureText","(Ljava/lang/String;III)F", (void*) PaintGlue::measureText_StringIII}, + {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC}, {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS}, - {"native_getTextWidths","(JJ[CIII[F)I", (void*) PaintGlue::getTextWidths___CIII_F}, - {"native_getTextWidths","(JJLjava/lang/String;III[F)I", - (void*) PaintGlue::getTextWidths__StringIII_F}, - {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F", - (void*) PaintGlue::getTextRunAdvances___CIIIIZ_FI}, - {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F", - (void*) PaintGlue::getTextRunAdvances__StringIIIIZ_FI}, + {"native_getTextAdvances","(JJ[CIIIII[FI)F", + (void*) PaintGlue::getTextAdvances___CIIIII_FI}, + {"native_getTextAdvances","(JJLjava/lang/String;IIIII[FI)F", + (void*) PaintGlue::getTextAdvances__StringIIIII_FI}, {"native_getTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C}, {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I", diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp index dbd7c89805ab..2998c99a273e 100644 --- a/core/jni/android/graphics/Path.cpp +++ b/core/jni/android/graphics/Path.cpp @@ -475,7 +475,7 @@ public: } }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"finalizer", "(J)V", (void*) SkPathGlue::finalizer}, {"init1","()J", (void*) SkPathGlue::init1}, {"init2","(J)J", (void*) SkPathGlue::init2}, diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp index 265944e216e2..b289b21a3d8b 100644 --- a/core/jni/android/graphics/PathEffect.cpp +++ b/core/jni/android/graphics/PathEffect.cpp @@ -69,31 +69,31 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gPathEffectMethods[] = { +static const JNINativeMethod gPathEffectMethods[] = { { "nativeDestructor", "(J)V", (void*)SkPathEffectGlue::destructor } }; -static JNINativeMethod gComposePathEffectMethods[] = { +static const JNINativeMethod gComposePathEffectMethods[] = { { "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Compose_constructor } }; -static JNINativeMethod gSumPathEffectMethods[] = { +static const JNINativeMethod gSumPathEffectMethods[] = { { "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Sum_constructor } }; -static JNINativeMethod gDashPathEffectMethods[] = { +static const JNINativeMethod gDashPathEffectMethods[] = { { "nativeCreate", "([FF)J", (void*)SkPathEffectGlue::Dash_constructor } }; -static JNINativeMethod gPathDashPathEffectMethods[] = { +static const JNINativeMethod gPathDashPathEffectMethods[] = { { "nativeCreate", "(JFFI)J", (void*)SkPathEffectGlue::OneD_constructor } }; -static JNINativeMethod gCornerPathEffectMethods[] = { +static const JNINativeMethod gCornerPathEffectMethods[] = { { "nativeCreate", "(F)J", (void*)SkPathEffectGlue::Corner_constructor } }; -static JNINativeMethod gDiscretePathEffectMethods[] = { +static const JNINativeMethod gDiscretePathEffectMethods[] = { { "nativeCreate", "(FF)J", (void*)SkPathEffectGlue::Discrete_constructor } }; diff --git a/core/jni/android/graphics/PathMeasure.cpp b/core/jni/android/graphics/PathMeasure.cpp index fec5d9db3a6a..70e528d4be6f 100644 --- a/core/jni/android/graphics/PathMeasure.cpp +++ b/core/jni/android/graphics/PathMeasure.cpp @@ -143,7 +143,7 @@ public: } }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"native_create", "(JZ)J", (void*) SkPathMeasureGlue::create }, {"native_setPath", "(JJZ)V", (void*) SkPathMeasureGlue::setPath }, {"native_getLength", "(J)F", (void*) SkPathMeasureGlue::getLength }, diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp index fed90a5d2f83..dfc3c9d7ed13 100644 --- a/core/jni/android/graphics/PorterDuff.cpp +++ b/core/jni/android/graphics/PorterDuff.cpp @@ -58,7 +58,7 @@ public: }; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"nativeCreateXfermode","(I)J", (void*) SkPorterDuffGlue::CreateXfermode}, }; diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp index cfc23ac8ecb3..a106ecfeb65f 100644 --- a/core/jni/android/graphics/Rasterizer.cpp +++ b/core/jni/android/graphics/Rasterizer.cpp @@ -61,7 +61,7 @@ public: } }; -static JNINativeMethod gRasterizerMethods[] = { +static const JNINativeMethod gRasterizerMethods[] = { {"finalizer", "(J)V", (void*) SkRasterizerGlue::finalizer} }; @@ -85,7 +85,7 @@ public: } }; -static JNINativeMethod gLayerRasterizerMethods[] = { +static const JNINativeMethod gLayerRasterizerMethods[] = { { "nativeConstructor", "()J", (void*)SkLayerRasterizerGlue::create }, { "nativeAddLayer", "(JJFF)V", (void*)SkLayerRasterizerGlue::addLayer } }; diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp index e99bdfcc63fa..bcd0b60308bb 100644 --- a/core/jni/android/graphics/Region.cpp +++ b/core/jni/android/graphics/Region.cpp @@ -306,13 +306,13 @@ static jboolean RegionIter_next(JNIEnv* env, jobject, jlong pairHandle, jobject //////////////////////////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gRegionIterMethods[] = { +static const JNINativeMethod gRegionIterMethods[] = { { "nativeConstructor", "(J)J", (void*)RegionIter_constructor }, { "nativeDestructor", "(J)V", (void*)RegionIter_destructor }, { "nativeNext", "(JLandroid/graphics/Rect;)Z", (void*)RegionIter_next } }; -static JNINativeMethod gRegionMethods[] = { +static const JNINativeMethod gRegionMethods[] = { // these are static methods { "nativeConstructor", "()J", (void*)Region_constructor }, { "nativeDestructor", "(J)V", (void*)Region_destructor }, diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index 49c377e9c97f..799ed835197d 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -240,36 +240,36 @@ static jlong ComposeShader_create2(JNIEnv* env, jobject o, /////////////////////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gColorMethods[] = { +static const JNINativeMethod gColorMethods[] = { { "nativeRGBToHSV", "(III[F)V", (void*)Color_RGBToHSV }, { "nativeHSVToColor", "(I[F)I", (void*)Color_HSVToColor } }; -static JNINativeMethod gShaderMethods[] = { +static const JNINativeMethod gShaderMethods[] = { { "nativeDestructor", "(J)V", (void*)Shader_destructor }, { "nativeSetLocalMatrix", "(JJ)J", (void*)Shader_setLocalMatrix } }; -static JNINativeMethod gBitmapShaderMethods[] = { +static const JNINativeMethod gBitmapShaderMethods[] = { { "nativeCreate", "(Landroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor }, }; -static JNINativeMethod gLinearGradientMethods[] = { +static const JNINativeMethod gLinearGradientMethods[] = { { "nativeCreate1", "(FFFF[I[FI)J", (void*)LinearGradient_create1 }, { "nativeCreate2", "(FFFFIII)J", (void*)LinearGradient_create2 }, }; -static JNINativeMethod gRadialGradientMethods[] = { +static const JNINativeMethod gRadialGradientMethods[] = { { "nativeCreate1", "(FFF[I[FI)J", (void*)RadialGradient_create1 }, { "nativeCreate2", "(FFFIII)J", (void*)RadialGradient_create2 }, }; -static JNINativeMethod gSweepGradientMethods[] = { +static const JNINativeMethod gSweepGradientMethods[] = { { "nativeCreate1", "(FF[I[F)J", (void*)SweepGradient_create1 }, { "nativeCreate2", "(FFII)J", (void*)SweepGradient_create2 }, }; -static JNINativeMethod gComposeShaderMethods[] = { +static const JNINativeMethod gComposeShaderMethods[] = { { "nativeCreate1", "(JJJ)J", (void*)ComposeShader_create1 }, { "nativeCreate2", "(JJI)J", (void*)ComposeShader_create2 }, }; diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index 80de52611735..61dc6e425ddf 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -359,7 +359,7 @@ static jboolean SurfaceTexture_isReleased(JNIEnv* env, jobject thiz) // ---------------------------------------------------------------------------- -static JNINativeMethod gSurfaceTextureMethods[] = { +static const JNINativeMethod gSurfaceTextureMethods[] = { {"nativeClassInit", "()V", (void*)SurfaceTexture_classInit }, {"nativeInit", "(ZIZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init }, {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index e0cbc9efbd18..e97b768dd0cc 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -68,7 +68,7 @@ static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) { /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gTypefaceMethods[] = { +static const JNINativeMethod gTypefaceMethods[] = { { "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface }, { "nativeCreateWeightAlias", "(JI)J", (void*)Typeface_createWeightAlias }, { "nativeUnref", "(J)V", (void*)Typeface_unref }, diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp index 4a424aeb09a3..7441acc95cea 100644 --- a/core/jni/android/graphics/Xfermode.cpp +++ b/core/jni/android/graphics/Xfermode.cpp @@ -47,15 +47,15 @@ public: /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gXfermodeMethods[] = { +static const JNINativeMethod gXfermodeMethods[] = { {"finalizer", "(J)V", (void*) SkXfermodeGlue::finalizer} }; -static JNINativeMethod gAvoidMethods[] = { +static const JNINativeMethod gAvoidMethods[] = { {"nativeCreate", "(III)J", (void*) SkXfermodeGlue::avoid_create} }; -static JNINativeMethod gPixelXorMethods[] = { +static const JNINativeMethod gPixelXorMethods[] = { {"nativeCreate", "(I)J", (void*) SkXfermodeGlue::pixelxor_create} }; diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp index 5eede2aee286..7d0c39cca018 100644 --- a/core/jni/android/graphics/YuvToJpegEncoder.cpp +++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp @@ -243,7 +243,7 @@ static jboolean YuvImage_compressToJpeg(JNIEnv* env, jobject, jbyteArray inYuv, } /////////////////////////////////////////////////////////////////////////////// -static JNINativeMethod gYuvImageMethods[] = { +static const JNINativeMethod gYuvImageMethods[] = { { "nativeCompressToJpeg", "([BIII[I[IILjava/io/OutputStream;[B)Z", (void*)YuvImage_compressToJpeg } }; diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp index a91b15b7fa41..7a13fe427b00 100644 --- a/core/jni/android/graphics/pdf/PdfDocument.cpp +++ b/core/jni/android/graphics/pdf/PdfDocument.cpp @@ -150,7 +150,7 @@ static void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) { document->close(); } -static JNINativeMethod gPdfDocument_Methods[] = { +static const JNINativeMethod gPdfDocument_Methods[] = { {"nativeCreateDocument", "()J", (void*) nativeCreateDocument}, {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage}, {"nativeFinishPage", "(J)V", (void*) nativeFinishPage}, diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp index 52b69e02e894..0177635f26b0 100644 --- a/core/jni/android/graphics/pdf/PdfEditor.cpp +++ b/core/jni/android/graphics/pdf/PdfEditor.cpp @@ -343,7 +343,7 @@ static void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, ji nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox); } -static JNINativeMethod gPdfEditor_Methods[] = { +static const JNINativeMethod gPdfEditor_Methods[] = { {"nativeOpen", "(IJ)J", (void*) nativeOpen}, {"nativeClose", "(J)V", (void*) nativeClose}, {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp index 006eef847a12..6ddfacf442e8 100644 --- a/core/jni/android/graphics/pdf/PdfRenderer.cpp +++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp @@ -283,7 +283,7 @@ static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong skBitmap.notifyPixelsChanged(); } -static JNINativeMethod gPdfRenderer_Methods[] = { +static const JNINativeMethod gPdfRenderer_Methods[] = { {"nativeCreate", "(IJ)J", (void*) nativeCreate}, {"nativeClose", "(J)V", (void*) nativeClose}, {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index 40029bbe0aee..e045f5f36ada 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -1087,18 +1087,18 @@ static jint etc1_getHeight(JNIEnv *env, jclass clazz, * JNI registration */ -static JNINativeMethod gMatrixMethods[] = { +static const JNINativeMethod gMatrixMethods[] = { { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM }, { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV }, }; -static JNINativeMethod gVisibilityMethods[] = { +static const JNINativeMethod gVisibilityMethods[] = { { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere }, { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres }, { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest }, }; -static JNINativeMethod gUtilsMethods[] = { +static const JNINativeMethod gUtilsMethods[] = { { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat }, { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType }, { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D }, @@ -1106,7 +1106,7 @@ static JNINativeMethod gUtilsMethods[] = { { "setTracingLevel", "(I)V", (void*)setTracingLevel }, }; -static JNINativeMethod gEtc1Methods[] = { +static const JNINativeMethod gEtc1Methods[] = { { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock }, { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock }, { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize }, @@ -1120,11 +1120,11 @@ static JNINativeMethod gEtc1Methods[] = { typedef struct _ClassRegistrationInfo { const char* classPath; - JNINativeMethod* methods; + const JNINativeMethod* methods; size_t methodCount; } ClassRegistrationInfo; -static ClassRegistrationInfo gClasses[] = { +static const ClassRegistrationInfo gClasses[] = { {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)}, {"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)}, {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)}, @@ -1136,7 +1136,7 @@ int register_android_opengl_classes(JNIEnv* env) nativeClassInitBuffer(env); int result = 0; for (int i = 0; i < NELEM(gClasses); i++) { - ClassRegistrationInfo* cri = &gClasses[i]; + const ClassRegistrationInfo* cri = &gClasses[i]; result = RegisterMethodsOrDie(env, cri->classPath, cri->methods, cri->methodCount); } return result; diff --git a/core/jni/android_animation_PropertyValuesHolder.cpp b/core/jni/android_animation_PropertyValuesHolder.cpp index d11774189901..6065c2473978 100644 --- a/core/jni/android_animation_PropertyValuesHolder.cpp +++ b/core/jni/android_animation_PropertyValuesHolder.cpp @@ -139,7 +139,7 @@ static void android_animation_PropertyValuesHolder_callMultipleIntMethod( env->ReleaseIntArrayElements(arg, intValues, JNI_ABORT); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nGetIntMethod", "(Ljava/lang/Class;Ljava/lang/String;)J", (void*)android_animation_PropertyValuesHolder_getIntMethod }, { "nGetFloatMethod", "(Ljava/lang/Class;Ljava/lang/String;)J", diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp index ef17db6b0fdf..36d78cf3aca0 100644 --- a/core/jni/android_content_res_ObbScanner.cpp +++ b/core/jni/android_content_res_ObbScanner.cpp @@ -76,7 +76,7 @@ static void android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "getObbInfo_native", "(Ljava/lang/String;Landroid/content/res/ObbInfo;)V", (void*) android_content_res_ObbScanner_getObbInfo }, diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp index 580ac02789c5..bb09d001037d 100644 --- a/core/jni/android_database_CursorWindow.cpp +++ b/core/jni/android_database_CursorWindow.cpp @@ -477,7 +477,7 @@ static jboolean nativePutNull(JNIEnv* env, jclass clazz, jlong windowPtr, return true; } -static JNINativeMethod sMethods[] = +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "(Ljava/lang/String;I)J", diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp index 7a3cdf68fb18..bcc3bb09b69d 100644 --- a/core/jni/android_database_SQLiteConnection.cpp +++ b/core/jni/android_database_SQLiteConnection.cpp @@ -786,7 +786,7 @@ static void nativeResetCancel(JNIEnv* env, jobject clazz, jlong connectionPtr, } -static JNINativeMethod sMethods[] = +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)J", diff --git a/core/jni/android_database_SQLiteDebug.cpp b/core/jni/android_database_SQLiteDebug.cpp index 26e13cf10e71..4e4c36cbb7e1 100644 --- a/core/jni/android_database_SQLiteDebug.cpp +++ b/core/jni/android_database_SQLiteDebug.cpp @@ -58,7 +58,7 @@ static void nativeGetPagerStats(JNIEnv *env, jobject clazz, jobject statsObj) * JNI registration. */ -static JNINativeMethod gMethods[] = +static const JNINativeMethod gMethods[] = { { "nativeGetPagerStats", "(Landroid/database/sqlite/SQLiteDebug$PagerStats;)V", (void*) nativeGetPagerStats }, diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp index 0a1c9f75edec..03e2387f24bc 100644 --- a/core/jni/android_database_SQLiteGlobal.cpp +++ b/core/jni/android_database_SQLiteGlobal.cpp @@ -75,7 +75,7 @@ static jint nativeReleaseMemory(JNIEnv* env, jclass clazz) { return sqlite3_release_memory(SOFT_HEAP_LIMIT); } -static JNINativeMethod sMethods[] = +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeReleaseMemory", "()I", (void*)nativeReleaseMemory }, diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp index ae96936ecba5..3e7a04efc536 100644 --- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp +++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp @@ -105,7 +105,7 @@ static jbyteArray DdmHandleNativeHeap_getLeakInfo(JNIEnv* env, jobject) { return array; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "getLeakInfo", "()[B", (void*) DdmHandleNativeHeap_getLeakInfo }, }; diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index 5ddf2350d278..32a877ae3398 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -746,7 +746,7 @@ static void freeTextLayoutCaches(JNIEnv* env, jobject) { }; // namespace CanvasJNI -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"finalizer", "(J)V", (void*) CanvasJNI::finalizer}, {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster}, {"native_setBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap}, diff --git a/core/jni/android_graphics_Picture.cpp b/core/jni/android_graphics_Picture.cpp index fd42ddb9226e..03fcdef8fbfe 100644 --- a/core/jni/android_graphics_Picture.cpp +++ b/core/jni/android_graphics_Picture.cpp @@ -91,7 +91,7 @@ static void android_graphics_Picture_endRecording(JNIEnv* env, jobject, jlong pi pict->endRecording(); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"nativeGetWidth", "(J)I", (void*) android_graphics_Picture_getWidth}, {"nativeGetHeight", "(J)I", (void*) android_graphics_Picture_getHeight}, {"nativeConstructor", "(J)J", (void*) android_graphics_Picture_newPicture}, diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 4f44c262f261..414eba79f22d 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -949,7 +949,7 @@ static void android_hardware_Camera_enableFocusMoveCallback(JNIEnv *env, jobject //------------------------------------------------- -static JNINativeMethod camMethods[] = { +static const JNINativeMethod camMethods[] = { { "getNumberOfCameras", "()I", (void *)android_hardware_Camera_getNumberOfCameras }, diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index 7d0afdcdd109..2e5cda069538 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -343,7 +343,7 @@ static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint } //---------------------------------------------------------------------------- -static JNINativeMethod gSystemSensorManagerMethods[] = { +static const JNINativeMethod gSystemSensorManagerMethods[] = { {"nativeClassInit", "()V", (void*)nativeClassInit }, @@ -360,7 +360,7 @@ static JNINativeMethod gSystemSensorManagerMethods[] = { (void*)nativeIsDataInjectionEnabled}, }; -static JNINativeMethod gBaseEventQueueMethods[] = { +static const JNINativeMethod gBaseEventQueueMethods[] = { {"nativeInitBaseEventQueue", "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J", (void*)nativeInitSensorEventQueue }, diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp index 2d2ff4d97cb9..393dc7b9f4fd 100644 --- a/core/jni/android_hardware_SerialPort.cpp +++ b/core/jni/android_hardware_SerialPort.cpp @@ -243,7 +243,7 @@ android_hardware_SerialPort_send_break(JNIEnv *env, jobject thiz) tcsendbreak(fd, 0); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { {"native_open", "(Ljava/io/FileDescriptor;I)V", (void *)android_hardware_SerialPort_open}, {"native_close", "()V", (void *)android_hardware_SerialPort_close}, diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp index 1c4c9ecc8a09..048b3c71c2c3 100644 --- a/core/jni/android_hardware_SoundTrigger.cpp +++ b/core/jni/android_hardware_SoundTrigger.cpp @@ -768,14 +768,14 @@ android_hardware_SoundTrigger_stopRecognition(JNIEnv *env, jobject thiz, return status; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"listModules", "(Ljava/util/ArrayList;)I", (void *)android_hardware_SoundTrigger_listModules}, }; -static JNINativeMethod gModuleMethods[] = { +static const JNINativeMethod gModuleMethods[] = { {"native_setup", "(Ljava/lang/Object;)V", (void *)android_hardware_SoundTrigger_setup}, diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp index ef3b6463cd97..89d33e2ace1c 100644 --- a/core/jni/android_hardware_UsbDevice.cpp +++ b/core/jni/android_hardware_UsbDevice.cpp @@ -44,7 +44,7 @@ android_hardware_UsbDevice_get_device_name(JNIEnv *env, jobject clazz, jint id) return result; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { // static methods { "native_get_device_id", "(Ljava/lang/String;)I", (void*)android_hardware_UsbDevice_get_device_id }, diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp index e0cae6f3136f..1ba9fc58800c 100644 --- a/core/jni/android_hardware_UsbDeviceConnection.cpp +++ b/core/jni/android_hardware_UsbDeviceConnection.cpp @@ -246,7 +246,7 @@ android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz) return result; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { {"native_open", "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z", (void *)android_hardware_UsbDeviceConnection_open}, {"native_close", "()V", (void *)android_hardware_UsbDeviceConnection_close}, diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp index ce99e15bffc0..399e7b16f073 100644 --- a/core/jni/android_hardware_UsbRequest.cpp +++ b/core/jni/android_hardware_UsbRequest.cpp @@ -190,7 +190,7 @@ android_hardware_UsbRequest_cancel(JNIEnv *env, jobject thiz) return (usb_request_cancel(request) == 0); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { {"native_init", "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z", (void *)android_hardware_UsbRequest_init}, {"native_close", "()V", (void *)android_hardware_UsbRequest_close}, diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp index fb2268911be3..793002734111 100644 --- a/core/jni/android_hardware_camera2_CameraMetadata.cpp +++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp @@ -529,7 +529,7 @@ static void CameraMetadata_writeToParcel(JNIEnv *env, jobject thiz, jobject parc //------------------------------------------------- -static JNINativeMethod gCameraMetadataMethods[] = { +static const JNINativeMethod gCameraMetadataMethods[] = { // static methods { "nativeClassInit", "()V", diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp index 8b69bbd084b5..738a62ad5772 100644 --- a/core/jni/android_hardware_camera2_DngCreator.cpp +++ b/core/jni/android_hardware_camera2_DngCreator.cpp @@ -2280,7 +2280,7 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject } /*extern "C" */ -static JNINativeMethod gDngCreatorMethods[] = { +static const JNINativeMethod gDngCreatorMethods[] = { {"nativeClassInit", "()V", (void*) DngCreator_nativeClassInit}, {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;" "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V", diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index 63915ed1c134..f1ea7ec7e8a2 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -730,7 +730,7 @@ static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz } // extern "C" -static JNINativeMethod gCameraDeviceMethods[] = { +static const JNINativeMethod gCameraDeviceMethods[] = { { "nativeDetectSurfaceType", "(Landroid/view/Surface;)I", (void *)LegacyCameraDevice_nativeDetectSurfaceType }, diff --git a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp index 7257597ca6cf..f0420585bfa4 100644 --- a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp +++ b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp @@ -302,7 +302,7 @@ static jlong PerfMeasurement_nativeGetNextGlDuration(JNIEnv* env, } // extern "C" -static JNINativeMethod gPerfMeasurementMethods[] = { +static const JNINativeMethod gPerfMeasurementMethods[] = { { "nativeCreateContext", "(I)J", (jlong *)PerfMeasurement_nativeCreateContext }, diff --git a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp index 470c5ba8e2a3..4b279f63c99f 100644 --- a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp +++ b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp @@ -275,7 +275,7 @@ static int flush(JNIEnv* env, jobject obj) { } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { // {"name", "signature", (void*) functionPointer }, { "nativeClassInit", "()V", (void*) class_init }, { "nativeInitialize", "()V", (void*) initialize }, diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 6c2bbd45ea51..b977e377f2f3 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -682,7 +682,7 @@ static void android_media_AudioRecord_disableDeviceCallback( // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { // name, signature, funcPtr {"native_start", "(II)I", (void *)android_media_AudioRecord_start}, {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 91b3278c2e2b..6d3c7d7363c6 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -1616,7 +1616,7 @@ android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz) // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters}, {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters}, {"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone}, @@ -1663,7 +1663,7 @@ static JNINativeMethod gMethods[] = { }; -static JNINativeMethod gEventHandlerMethods[] = { +static const JNINativeMethod gEventHandlerMethods[] = { {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_AudioSystem_eventHandlerSetup}, diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 5faa15008359..7860b74cc804 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -1052,7 +1052,7 @@ static void android_media_AudioTrack_disableDeviceCallback( // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { // name, signature, funcPtr {"native_start", "()V", (void *)android_media_AudioTrack_start}, {"native_stop", "()V", (void *)android_media_AudioTrack_stop}, diff --git a/core/jni/android_media_JetPlayer.cpp b/core/jni/android_media_JetPlayer.cpp index d441f1015dfc..873c3f2e07e1 100644 --- a/core/jni/android_media_JetPlayer.cpp +++ b/core/jni/android_media_JetPlayer.cpp @@ -488,7 +488,7 @@ android_media_JetPlayer_clearQueue(JNIEnv *env, jobject thiz) // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { // name, signature, funcPtr {"native_setup", "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup}, {"native_finalize", "()V", (void *)android_media_JetPlayer_finalize}, diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp index 9bc223b57a42..bd1a6ecaf95c 100644 --- a/core/jni/android_media_RemoteDisplay.cpp +++ b/core/jni/android_media_RemoteDisplay.cpp @@ -177,7 +177,7 @@ static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) { // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"nativeListen", "(Ljava/lang/String;Ljava/lang/String;)J", (void*)nativeListen }, {"nativeDispose", "(J)V", diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp index 243f0400775e..aec62631c559 100644 --- a/core/jni/android_media_ToneGenerator.cpp +++ b/core/jni/android_media_ToneGenerator.cpp @@ -123,7 +123,7 @@ static void android_media_ToneGenerator_native_finalize(JNIEnv *env, // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "startTone", "(II)Z", (void *)android_media_ToneGenerator_startTone }, { "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone }, { "getAudioSessionId", "()I", (void *)android_media_ToneGenerator_getAudioSessionId}, diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp index c137b17426e0..d6d431019a6d 100644 --- a/core/jni/android_net_LocalSocketImpl.cpp +++ b/core/jni/android_net_LocalSocketImpl.cpp @@ -495,7 +495,7 @@ static jobject socket_get_peer_credentials(JNIEnv *env, /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V", (void*)socket_connect_local}, diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index fada7ac21b1d..ba0876d74b17 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -302,7 +302,7 @@ static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jin /* * JNI registration. */ -static JNINativeMethod gNetworkUtilMethods[] = { +static const JNINativeMethod gNetworkUtilMethods[] = { /* name, signature, funcPtr */ { "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections }, { "startDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcp }, diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 735441743516..7b7d0cf498c3 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -185,7 +185,7 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { } } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"nativeGetTotalStat", "(I)J", (void*) getTotalStat}, {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat}, {"nativeGetUidStat", "(II)J", (void*) getUidStat}, diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp index 9f5b3bc3f5b2..568473c14dc5 100644 --- a/core/jni/android_opengl_EGL14.cpp +++ b/core/jni/android_opengl_EGL14.cpp @@ -1231,7 +1231,7 @@ android_eglCopyBuffers static const char *classPathName = "android/opengl/EGL14"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"eglGetError", "()I", (void *) android_eglGetError }, {"eglGetDisplay", "(I)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplayInt }, diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp index 60a3bf642915..62ccad4d85f0 100644 --- a/core/jni/android_opengl_EGLExt.cpp +++ b/core/jni/android_opengl_EGLExt.cpp @@ -149,7 +149,7 @@ android_eglPresentationTimeANDROID static const char *classPathName = "android/opengl/EGLExt"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"eglPresentationTimeANDROID", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;J)Z", (void *) android_eglPresentationTimeANDROID }, }; diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp index dac98defbc79..f4135c213e36 100644 --- a/core/jni/android_opengl_GLES10.cpp +++ b/core/jni/android_opengl_GLES10.cpp @@ -3184,7 +3184,7 @@ android_glViewport__IIII static const char *classPathName = "android/opengl/GLES10"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I }, {"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF }, diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp index 95be11bde598..4dc42339b6e5 100644 --- a/core/jni/android_opengl_GLES10Ext.cpp +++ b/core/jni/android_opengl_GLES10Ext.cpp @@ -582,7 +582,7 @@ exit: static const char *classPathName = "android/opengl/GLES10Ext"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glQueryMatrixxOES", "([II[II)I", (void *) android_glQueryMatrixxOES___3II_3II }, {"glQueryMatrixxOES", "(Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)I", (void *) android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 }, diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp index 6970a3c7e180..2625e03c962e 100644 --- a/core/jni/android_opengl_GLES11.cpp +++ b/core/jni/android_opengl_GLES11.cpp @@ -3065,7 +3065,7 @@ android_glVertexPointer__IIII static const char *classPathName = "android/opengl/GLES11"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glBindBuffer", "(II)V", (void *) android_glBindBuffer__II }, {"glBufferData", "(IILjava/nio/Buffer;I)V", (void *) android_glBufferData__IILjava_nio_Buffer_2I }, diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp index 6422ff28e190..fb85cb0f8d95 100644 --- a/core/jni/android_opengl_GLES11Ext.cpp +++ b/core/jni/android_opengl_GLES11Ext.cpp @@ -3573,7 +3573,7 @@ android_glGetTexGenxvOES__IILjava_nio_IntBuffer_2 static const char *classPathName = "android/opengl/GLES11Ext"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glBlendEquationSeparateOES", "(II)V", (void *) android_glBlendEquationSeparateOES__II }, {"glBlendFuncSeparateOES", "(IIII)V", (void *) android_glBlendFuncSeparateOES__IIII }, diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp index f9a0dfeb444c..b9f61a91ec90 100644 --- a/core/jni/android_opengl_GLES20.cpp +++ b/core/jni/android_opengl_GLES20.cpp @@ -6152,7 +6152,7 @@ android_glViewport__IIII static const char *classPathName = "android/opengl/GLES20"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I }, {"glAttachShader", "(II)V", (void *) android_glAttachShader__II }, diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp index 1d92cd46527a..8eb50444762c 100644 --- a/core/jni/android_opengl_GLES30.cpp +++ b/core/jni/android_opengl_GLES30.cpp @@ -5167,7 +5167,7 @@ android_glGetInternalformativ__IIIILjava_nio_IntBuffer_2 static const char *classPathName = "android/opengl/GLES30"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glReadBuffer", "(I)V", (void *) android_glReadBuffer__I }, {"glDrawRangeElements", "(IIIIILjava/nio/Buffer;)V", (void *) android_glDrawRangeElements__IIIIILjava_nio_Buffer_2 }, diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp index 92ecbe0b99df..e427388a10e9 100644 --- a/core/jni/android_opengl_GLES31.cpp +++ b/core/jni/android_opengl_GLES31.cpp @@ -3175,7 +3175,7 @@ android_glVertexBindingDivisor__II static const char *classPathName = "android/opengl/GLES31"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glDispatchCompute", "(III)V", (void *) android_glDispatchCompute__III }, {"glDispatchComputeIndirect", "(J)V", (void *) android_glDispatchComputeIndirect }, diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp index 28563089e85a..180c69348853 100644 --- a/core/jni/android_opengl_GLES31Ext.cpp +++ b/core/jni/android_opengl_GLES31Ext.cpp @@ -1443,7 +1443,7 @@ android_glTexBufferRangeEXT__IIIII static const char *classPathName = "android/opengl/GLES31Ext"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glBlendBarrierKHR", "()V", (void *) android_glBlendBarrierKHR__ }, {"glDebugMessageControlKHR", "(IIII[IIZ)V", (void *) android_glDebugMessageControlKHR__IIII_3IIZ }, diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index b969477bf258..097bbac84e3f 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -973,7 +973,7 @@ static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject claz * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "getNativeHeapSize", "()J", (void*) android_os_Debug_getNativeHeapSize }, { "getNativeHeapAllocatedSize", "()J", diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp index d2db3c9ab5b3..e57a7190cfce 100644 --- a/core/jni/android_os_MessageQueue.cpp +++ b/core/jni/android_os_MessageQueue.cpp @@ -209,7 +209,7 @@ static void android_os_MessageQueue_nativeSetFileDescriptorEvents(JNIEnv* env, j // ---------------------------------------------------------------------------- -static JNINativeMethod gMessageQueueMethods[] = { +static const JNINativeMethod gMessageQueueMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit }, { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy }, diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp index 762b88f5dbee..8ba77aed1d04 100644 --- a/core/jni/android_os_SELinux.cpp +++ b/core/jni/android_os_SELinux.cpp @@ -320,7 +320,7 @@ static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr, jin /* * JNI registration. */ -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { /* name, signature, funcPtr */ { "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess }, { "getContext" , "()Ljava/lang/String;" , (void*)getCon }, diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp index dfe024e8a473..d98407deb7e7 100644 --- a/core/jni/android_os_SystemClock.cpp +++ b/core/jni/android_os_SystemClock.cpp @@ -104,7 +104,7 @@ static jlong android_os_SystemClock_elapsedRealtimeNano(JNIEnv* env, /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "uptimeMillis", "()J", (void*) android_os_SystemClock_uptimeMillis }, diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp index 554d304290cf..5dace6b7e536 100644 --- a/core/jni/android_os_SystemProperties.cpp +++ b/core/jni/android_os_SystemProperties.cpp @@ -220,7 +220,7 @@ static void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz) } } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "native_get", "(Ljava/lang/String;)Ljava/lang/String;", (void*) SystemProperties_getS }, { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp index 3fd3b3c9ae15..30fc47bba751 100644 --- a/core/jni/android_os_Trace.cpp +++ b/core/jni/android_os_Trace.cpp @@ -105,7 +105,7 @@ static void android_os_Trace_nativeSetTracingEnabled(JNIEnv* env, atrace_set_tracing_enabled(enabled); } -static JNINativeMethod gTraceMethods[] = { +static const JNINativeMethod gTraceMethods[] = { /* name, signature, funcPtr */ { "nativeGetEnabledTags", "()J", diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp index eb36f8549cfa..30d40a2a08ad 100644 --- a/core/jni/android_os_UEventObserver.cpp +++ b/core/jni/android_os_UEventObserver.cpp @@ -103,7 +103,7 @@ static void nativeRemoveMatch(JNIEnv* env, jclass clazz, jstring matchStr) { } } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeSetup", "()V", (void *)nativeSetup }, { "nativeWaitForNextEvent", "()Ljava/lang/String;", diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp index ca21fd716a5f..818bf53d97a4 100644 --- a/core/jni/android_server_NetworkManagementSocketTagger.cpp +++ b/core/jni/android_server_NetworkManagementSocketTagger.cpp @@ -83,7 +83,7 @@ static jint QTagUid_deleteTagData(JNIEnv* env, jclass, return (jint)res; } -static JNINativeMethod gQTagUidMethods[] = { +static const JNINativeMethod gQTagUidMethods[] = { { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)QTagUid_tagSocketFd}, { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)QTagUid_untagSocketFd}, { "native_setCounterSet", "(II)I", (void*)QTagUid_setCounterSet}, diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp index 328542954efa..2a3f0361a9cd 100644 --- a/core/jni/android_text_AndroidBidi.cpp +++ b/core/jni/android_text_AndroidBidi.cpp @@ -56,7 +56,7 @@ static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray, return result; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "runBidi", "(I[C[BIZ)I", (void*) runBidi } }; diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp index 9258248083d0..474a74e8776c 100644 --- a/core/jni/android_text_AndroidCharacter.cpp +++ b/core/jni/android_text_AndroidCharacter.cpp @@ -178,7 +178,7 @@ static jchar getMirror(JNIEnv* env, jobject obj, jchar c) return u_charMirror(c); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "getDirectionalities", "([C[BI)V", (void*) getDirectionalities }, { "getEastAsianWidth", "(C)I", diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp index a94ea8b06ed8..83f76eab053d 100644 --- a/core/jni/android_text_StaticLayout.cpp +++ b/core/jni/android_text_StaticLayout.cpp @@ -180,7 +180,7 @@ static void nGetWidths(JNIEnv* env, jclass, jlong nativePtr, jfloatArray widths) env->SetFloatArrayRegion(widths, 0, b->size(), b->charWidths()); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { // TODO performance: many of these are candidates for fast jni, awaiting guidance {"nNewBuilder", "()J", (void*) nNewBuilder}, {"nFreeBuilder", "(J)V", (void*) nFreeBuilder}, diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 7ca0654f9656..614e82f803ff 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -2112,7 +2112,7 @@ static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, /* * JNI registration. */ -static JNINativeMethod gAssetManagerMethods[] = { +static const JNINativeMethod gAssetManagerMethods[] = { /* name, signature, funcPtr */ // Basic asset stuff. diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp index 05bc12563b6c..4f8a2cb91506 100644 --- a/core/jni/android_util_EventLog.cpp +++ b/core/jni/android_util_EventLog.cpp @@ -249,7 +249,7 @@ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz UNUSED, /* * JNI registration. */ -static JNINativeMethod gRegisterMethods[] = { +static const JNINativeMethod gRegisterMethods[] = { /* name, signature, funcPtr */ { "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer }, { "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long }, diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp index 067d298580bc..2b93b6d61905 100644 --- a/core/jni/android_util_FileObserver.cpp +++ b/core/jni/android_util_FileObserver.cpp @@ -127,7 +127,7 @@ static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, ji #endif } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "init", "()I", (void*)android_os_fileobserver_init }, { "observe", "(I)V", (void*)android_os_fileobserver_observe }, diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp index 2b1067bede5d..2d23cda5ff15 100644 --- a/core/jni/android_util_Log.cpp +++ b/core/jni/android_util_Log.cpp @@ -111,7 +111,7 @@ static jint android_util_Log_println_native(JNIEnv* env, jobject clazz, /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable }, { "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native }, diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp index f83eaec409d5..b396afe62dff 100644 --- a/core/jni/android_util_StringBlock.cpp +++ b/core/jni/android_util_StringBlock.cpp @@ -155,7 +155,7 @@ static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz /* * JNI registration. */ -static JNINativeMethod gStringBlockMethods[] = { +static const JNINativeMethod gStringBlockMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "([BII)J", (void*) android_content_StringBlock_nativeCreate }, diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp index 375710e6faca..7ae51c89fab7 100644 --- a/core/jni/android_util_XmlBlock.cpp +++ b/core/jni/android_util_XmlBlock.cpp @@ -364,7 +364,7 @@ static void android_content_XmlBlock_nativeDestroy(JNIEnv* env, jobject clazz, /* * JNI registration. */ -static JNINativeMethod gXmlBlockMethods[] = { +static const JNINativeMethod gXmlBlockMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "([BII)J", (void*) android_content_XmlBlock_nativeCreate }, diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 0e2ec6b85209..437bd192b70a 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -259,7 +259,7 @@ static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) { } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J", diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp index 17d2a5eddbf8..7682dd6ca8e3 100644 --- a/core/jni/android_view_GraphicBuffer.cpp +++ b/core/jni/android_view_GraphicBuffer.cpp @@ -268,7 +268,7 @@ sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) { const char* const kClassPathName = "android/view/GraphicBuffer"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreateGraphicBuffer", "(IIII)J", (void*) android_view_GraphiceBuffer_create }, { "nDestroyGraphicBuffer", "(J)V", (void*) android_view_GraphiceBuffer_destroy }, diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp index 36ba892b51c4..3a0ddc9fa825 100644 --- a/core/jni/android_view_HardwareLayer.cpp +++ b/core/jni/android_view_HardwareLayer.cpp @@ -85,7 +85,7 @@ static void android_view_HardwareLayer_updateSurfaceTexture(JNIEnv* env, jobject const char* const kClassPathName = "android/view/HardwareLayer"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nPrepare", "(JIIZ)Z", (void*) android_view_HardwareLayer_prepare }, { "nSetLayerPaint", "(JJ)V", (void*) android_view_HardwareLayer_setLayerPaint }, { "nSetTransform", "(JJ)V", (void*) android_view_HardwareLayer_setTransform }, diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index 4b42ab5d213a..092ac27176cc 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -259,7 +259,7 @@ static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobjec // ---------------------------------------------------------------------------- -static JNINativeMethod gInputChannelMethods[] = { +static const JNINativeMethod gInputChannelMethods[] = { /* name, signature, funcPtr */ { "nativeOpenInputChannelPair", "(Ljava/lang/String;)[Landroid/view/InputChannel;", (void*)android_view_InputChannel_nativeOpenInputChannelPair }, diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index 43b847108a20..8293cd8ff88d 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -395,7 +395,7 @@ static jboolean nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jlong } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J", diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index d61dee7a7673..3bd6917aedfa 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -289,7 +289,7 @@ static jboolean nativeSendMotionEvent(JNIEnv* env, jclass clazz, jlong senderPtr } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J", diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp index 7653f58778dd..e5519a752c39 100644 --- a/core/jni/android_view_KeyCharacterMap.cpp +++ b/core/jni/android_view_KeyCharacterMap.cpp @@ -203,7 +203,7 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, * JNI registration. */ -static JNINativeMethod g_methods[] = { +static const JNINativeMethod g_methods[] = { /* name, signature, funcPtr */ { "nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel }, diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 98c17c03b1a7..81d46c3d6988 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -752,7 +752,7 @@ static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass cl // ---------------------------------------------------------------------------- -static JNINativeMethod gMotionEventMethods[] = { +static const JNINativeMethod gMotionEventMethods[] = { /* name, signature, funcPtr */ { "nativeInitialize", "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;" diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index a3b370017a8e..388d36541eb8 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -467,7 +467,7 @@ static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz, const char* const kClassPathName = "android/view/RenderNode"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreate", "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create }, { "nDestroyRenderNode", "(J)V", (void*) android_view_RenderNode_destroyRenderNode }, { "nSetDisplayListData", "(JJ)V", (void*) android_view_RenderNode_setDisplayListData }, diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp index 4177ee2f7fe8..0926e9b76691 100644 --- a/core/jni/android_view_RenderNodeAnimator.cpp +++ b/core/jni/android_view_RenderNodeAnimator.cpp @@ -193,7 +193,7 @@ static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) { const char* const kClassPathName = "android/view/RenderNodeAnimator"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreateAnimator", "(IF)J", (void*) createAnimator }, { "nCreateCanvasPropertyFloatAnimator", "(JF)J", (void*) createCanvasPropertyFloatAnimator }, { "nCreateCanvasPropertyPaintAnimator", "(JIF)J", (void*) createCanvasPropertyPaintAnimator }, diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 4a311d31bd82..24055e76234e 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -514,7 +514,7 @@ static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) { namespace hwui = android::uirenderer; -static JNINativeMethod gSurfaceMethods[] = { +static const JNINativeMethod gSurfaceMethods[] = { {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J", (void*)nativeCreateFromSurfaceTexture }, {"nativeRelease", "(J)V", diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index d1acb59a6411..65ebb6633a8f 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -572,7 +572,7 @@ static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject // ---------------------------------------------------------------------------- -static JNINativeMethod sSurfaceControlMethods[] = { +static const JNINativeMethod sSurfaceControlMethods[] = { {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)J", (void*)nativeCreate }, {"nativeRelease", "(J)V", diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp index 609c565678f2..dad6958560c0 100644 --- a/core/jni/android_view_SurfaceSession.cpp +++ b/core/jni/android_view_SurfaceSession.cpp @@ -56,7 +56,7 @@ static void nativeKill(JNIEnv* env, jclass clazz, jlong ptr) { } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeCreate", "()J", (void*)nativeCreate }, diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp index beb83b1e01fa..b736a17c1199 100644 --- a/core/jni/android_view_TextureView.cpp +++ b/core/jni/android_view_TextureView.cpp @@ -197,7 +197,7 @@ static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject, const char* const kClassPathName = "android/view/TextureView"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V", (void*) android_view_TextureView_createNativeWindow }, { "nDestroyNativeWindow", "()V", diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 9a2703ba2ed3..c79f833b54a9 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -484,7 +484,7 @@ static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, job const char* const kClassPathName = "android/view/ThreadedRenderer"; -static JNINativeMethod gMethods[] = { +static const 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 }, diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp index ddd5fc853d25..04ec7059365e 100644 --- a/core/jni/android_view_VelocityTracker.cpp +++ b/core/jni/android_view_VelocityTracker.cpp @@ -215,7 +215,7 @@ static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jcl // --- JNI Registration --- -static JNINativeMethod gVelocityTrackerMethods[] = { +static const JNINativeMethod gVelocityTrackerMethods[] = { /* name, signature, funcPtr */ { "nativeInitialize", "(Ljava/lang/String;)J", diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index daa6f82ea122..364ac44ee0f6 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -561,7 +561,7 @@ com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlon delete reinterpret_cast<ZipFileRO*>(apkHandle); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"nativeOpenApk", "(Ljava/lang/String;)J", (void *)com_android_internal_content_NativeLibraryHelper_openApk}, diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 6c0b756591f7..70134ab04a2a 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -284,7 +284,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, return 0; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I", (void*) readNetworkStatsDetail } diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index aef70be4922a..3f1be456c199 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -647,7 +647,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( return pid; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize }, diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp index 7a18c2d380ce..d20bae232656 100644 --- a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp +++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp @@ -36,7 +36,7 @@ static void decStrong(JNIEnv* env, jobject clazz, jlong objPtr) { const char* const kClassPathName = "com/android/internal/util/VirtualRefBasePtr"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nIncStrong", "(J)V", (void*) incStrong }, { "nDecStrong", "(J)V", (void*) decStrong }, }; diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp index 2c65d6210c2e..6781e130c860 100644 --- a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp +++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp @@ -78,7 +78,7 @@ static jlong createLutInterpolator(JNIEnv* env, jobject clazz, jfloatArray jlut) const char* const kClassPathName = "com/android/internal/view/animation/NativeInterpolatorFactoryHelper"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "createAccelerateDecelerateInterpolator", "()J", (void*) createAccelerateDecelerateInterpolator }, { "createAccelerateInterpolator", "(F)J", (void*) createAccelerateInterpolator }, { "createAnticipateInterpolator", "(F)J", (void*) createAnticipateInterpolator }, diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp index baeb7dd98bc4..3d63b013e9f1 100644 --- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp @@ -532,7 +532,7 @@ static const char *classPathName = "com/google/android/gles_jni/EGLImpl"; #define OBJECT "Ljava/lang/Object;" #define STRING "Ljava/lang/String;" -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit","()V", (void*)nativeClassInit }, {"eglWaitGL", "()Z", (void*)jni_eglWaitGL }, {"eglInitialize", "(" DISPLAY "[I)Z", (void*)jni_eglInitialize }, diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp index f15f957d21c7..ad7d744cb693 100644 --- a/core/jni/com_google_android_gles_jni_GLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp @@ -8490,7 +8490,7 @@ android_glTexGenxv__IILjava_nio_IntBuffer_2 static const char *classPathName = "com/google/android/gles_jni/GLImpl"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nativeClassInit", "()V", (void*)nativeClassInit }, {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I }, {"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 664e62121d1b..148e7c109601 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -65,6 +65,7 @@ <protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" /> <protected-broadcast android:name="android.intent.action.REBOOT" /> <protected-broadcast android:name="android.intent.action.DOCK_EVENT" /> + <protected-broadcast android:name="android.intent.action.THERMAL_EVENT" /> <protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" /> <protected-broadcast android:name="android.intent.action.USER_ADDED" /> <protected-broadcast android:name="android.intent.action.USER_REMOVED" /> @@ -188,7 +189,7 @@ <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" /> <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" /> <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> - <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /> + <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_DETACHED" /> <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" /> @@ -1714,7 +1715,7 @@ android:protectionLevel="signature|privileged" /> <!-- Allows applications to change network connectivity state. - <p>Protection level: normal + <p>Protection level: signature --> <permission android:name="android.permission.CHANGE_NETWORK_STATE" android:description="@string/permdesc_changeNetworkState" @@ -2529,6 +2530,12 @@ android:label="@string/permlab_access_notification_policy" android:protectionLevel="normal" /> + <!-- Allows modification of do not disturb rules and policies. Only allowed for system + processes. + @hide --> + <permission android:name="android.permission.MANAGE_NOTIFICATIONS" + android:protectionLevel="signature" /> + <!-- Allows access to keyguard secure storage. Only allowed for system processes. @hide --> <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" diff --git a/core/res/res/color/btn_colored_material.xml b/core/res/res/color/btn_colored_background_material.xml index b45f824c835a..b7f0ef520ff7 100644 --- a/core/res/res/color/btn_colored_material.xml +++ b/core/res/res/color/btn_colored_background_material.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The Android Open Source Project +<!-- 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. @@ -14,6 +14,7 @@ limitations under the License. --> +<!-- Used for tha background of a bordered colored button. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:alpha="?attr/disabledAlpha" diff --git a/core/res/res/color/btn_colored_borderless_text_material.xml b/core/res/res/color/btn_colored_borderless_text_material.xml new file mode 100644 index 000000000000..ee5a90cc8c9b --- /dev/null +++ b/core/res/res/color/btn_colored_borderless_text_material.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. +--> + +<!-- Used for the text of a borderless colored button. --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:alpha="?attr/disabledAlpha" + android:color="?attr/textColorSecondary" /> + <item android:color="?attr/colorAccent"/> +</selector> diff --git a/core/res/res/color/btn_colored_text_material.xml b/core/res/res/color/btn_colored_text_material.xml index 950d04a68b45..c80fea62ef30 100644 --- a/core/res/res/color/btn_colored_text_material.xml +++ b/core/res/res/color/btn_colored_text_material.xml @@ -14,9 +14,10 @@ limitations under the License. --> +<!-- Used for the text of a bordered colored button. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:alpha="?attr/disabledAlpha" - android:color="?attr/textColorSecondary" /> - <item android:color="?attr/colorAccent"/> + android:color="?attr/textColorPrimary" /> + <item android:color="?attr/textColorPrimaryInverse" /> </selector> diff --git a/core/res/res/drawable/btn_colored_material.xml b/core/res/res/drawable/btn_colored_material.xml index 81cbe393bf80..c3c5760f2cc5 100644 --- a/core/res/res/drawable/btn_colored_material.xml +++ b/core/res/res/drawable/btn_colored_material.xml @@ -22,7 +22,7 @@ <ripple android:color="?attr/colorControlHighlight"> <item> <shape android:shape="rectangle" - android:tint="@color/btn_colored_material"> + android:tint="@color/btn_colored_background_material"> <corners android:radius="@dimen/control_corner_material" /> <solid android:color="@color/white" /> <padding android:left="@dimen/button_padding_horizontal_material" diff --git a/core/res/res/layout/docked_stack_divider.xml b/core/res/res/layout/docked_stack_divider.xml new file mode 100644 index 000000000000..aa6e68d57af9 --- /dev/null +++ b/core/res/res/layout/docked_stack_divider.xml @@ -0,0 +1,21 @@ +<?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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="@dimen/docked_stack_divider_thickness" + android:layout_height="match_parent" + android:background="@android:color/black" + /> diff --git a/core/res/res/layout/number_picker_material.xml b/core/res/res/layout/number_picker_material.xml index 47edec475aa7..b0455857e79e 100644 --- a/core/res/res/layout/number_picker_material.xml +++ b/core/res/res/layout/number_picker_material.xml @@ -22,4 +22,4 @@ android:gravity="center" android:singleLine="true" android:background="@null" - android:textAppearance="@style/TextAppearance.Material.Caption" /> + android:textAppearance="@style/TextAppearance.Material.Body1" /> diff --git a/core/res/res/layout/popup_menu_header_item_layout.xml b/core/res/res/layout/popup_menu_header_item_layout.xml new file mode 100644 index 000000000000..5879f85fbd6c --- /dev/null +++ b/core/res/res/layout/popup_menu_header_item_layout.xml @@ -0,0 +1,35 @@ +<?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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="?attr/dropdownListPreferredItemHeight" + android:minWidth="196dip" + android:paddingStart="16dip" + android:paddingEnd="16dip"> + + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?attr/textAppearancePopupMenuHeader" + android:layout_gravity="center_vertical" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:textAlignment="viewStart" /> + +</FrameLayout> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index a08f040ff716..2f1627b29c0f 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -227,23 +227,23 @@ <string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string> <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string> <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string> - <string name="permgroupdesc_contacts" msgid="6951499528303668046">"gaan by jou kontakte in"</string> + <string name="permgroupdesc_contacts" msgid="6951499528303668046">"in te gaan by jou kontakte"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Ligging"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"verkry toegang tot hierdie toestel se ligging"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"toegang te verkry tot hierdie toestel se ligging"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string> - <string name="permgroupdesc_calendar" msgid="3889615280211184106">"gaan by jou kalender in"</string> + <string name="permgroupdesc_calendar" msgid="3889615280211184106">"by jou kalender in te gaan"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> - <string name="permgroupdesc_sms" msgid="4656988620100940350">"stuur en bekyk SMS-boodskappe"</string> + <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS-boodskappe te stuur en te bekyk"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Stoor"</string> - <string name="permgroupdesc_storage" msgid="637758554581589203">"verkry toegang tot foto\'s, media en lêers op jou toestel"</string> + <string name="permgroupdesc_storage" msgid="637758554581589203">"toegang te verkry tot foto\'s, media en lêers op jou toestel"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofoon"</string> - <string name="permgroupdesc_microphone" msgid="4988812113943554584">"neem oudio op"</string> + <string name="permgroupdesc_microphone" msgid="4988812113943554584">"oudio op te neem"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"neem foto\'s en neem video op"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"foto\'s en video te neem"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Foon"</string> - <string name="permgroupdesc_phone" msgid="6234224354060641055">"maak en bestuur foonoproepe"</string> + <string name="permgroupdesc_phone" msgid="6234224354060641055">"foonoproepe te maak en te bestuur"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Liggaamsensors"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"kry toegang tot sensordata oor jou lewenstekens"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"toegang te verkry tot sensordata oor jou lewenstekens"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Haal venster-inhoud op"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Ondersoek die inhoud van \'n venster waarmee jy interaksie het."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Skakel Verken deur raak aan"</string> @@ -272,7 +272,7 @@ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Laat die program toe om seluitsending-boodskappe te lees wat deur jou toestel ontvang word. Seluitsending-waarskuwings word in sommige plekke afgelewer om jou van noodsituasies te waarsku. Kwaadwillige programme mag inmeng met die prestasie of die werking van jou toestel wanneer \'n noodgeval se seluitsending ontvang word."</string> <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lees ingetekende nuus"</string> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Laat die program toe om details oor die tans gesinkroniseerde strome te kry."</string> - <string name="permlab_sendSms" msgid="7544599214260982981">"stuur en bekyk SMS-boodskappe"</string> + <string name="permlab_sendSms" msgid="7544599214260982981">"SMS-boodskappe te stuur en te bekyk"</string> <string name="permdesc_sendSms" msgid="7094729298204937667">"Laat die program toe om SMS-boodskappe te stuur. Dit kan tot onverwagse heffings lei. Kwaadwillige programme kan jou geld kos deur boodskappe sonder jou bevestiging te stuur."</string> <string name="permlab_readSms" msgid="8745086572213270480">"lees jou teksboodskappe (SMS of MMS)"</string> <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Laat die program toe om SMS-boodskappe wat op jou tablet of SIM-kaart gestoor is, te lees. Dit laat die program toe om alle SMS-boodskappe te lees, ongeag van die inhoud of vertroulikheid daarvan."</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index cd6bb4b5a6e3..7b05612ab3e2 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -231,7 +231,7 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"přístup ke kontaktům"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"přístup k poloze tohoto zařízení"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"přístup k poloze tohoto zařízení"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendář"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"přístup ke kalendáři"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index e718935269bc..60f05020a3f0 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -493,8 +493,8 @@ <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Dette giver indehaveren mulighed for at knytte sig til det øverste grænsefladeniveau for et mobilselskabs beskedtjeneste. Dette bør ikke være nødvendigt i normale apps."</string> <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"knytte til tjenester fra mobilselskabet"</string> <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Tillader, at brugeren knytter sig til tjenester fra mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string> - <string name="permlab_access_notification_policy" msgid="4247510821662059671">"Adgang til Vil ikke forstyrres"</string> - <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Giver appen tilladelse til at læse og skrive konfigurationen af Vil ikke forstyrres."</string> + <string name="permlab_access_notification_policy" msgid="4247510821662059671">"have adgang til Forstyr ikke"</string> + <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Giver appen tilladelse til at læse og skrive konfigurationen af Forstyr ikke."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Angiv regler for adgangskoder"</string> <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollér længden samt tilladte tegn i adgangskoder og pinkoder til skærmlåsen."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string> @@ -1471,10 +1471,10 @@ </plurals> <string name="zen_mode_until" msgid="7336308492289875088">"Indtil <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Indtil du slår denne indstilling fra"</string> - <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Indtil du slår \"Vil ikke forstyrres\" fra"</string> + <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Indtil du slår \"Forstyr ikke\" fra"</string> <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string> <string name="toolbar_collapse_description" msgid="2821479483960330739">"Skjul"</string> - <string name="zen_mode_feature_name" msgid="5254089399895895004">"Vil ikke forstyrres"</string> + <string name="zen_mode_feature_name" msgid="5254089399895895004">"Forstyr ikke"</string> <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Nedetid"</string> <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Hverdagsaften"</string> <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Weekend"</string> diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml index 2c7a64dab5c8..8e7193a2037f 100644 --- a/core/res/res/values-eu-rES/strings.xml +++ b/core/res/res/values-eu-rES/strings.xml @@ -227,23 +227,23 @@ <string name="user_owner_label" msgid="2804351898001038951">"Pertsonalak"</string> <string name="managed_profile_label" msgid="6260850669674791528">"Lana"</string> <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string> - <string name="permgroupdesc_contacts" msgid="6951499528303668046">"Atzitu kontaktuak"</string> + <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktuak atzitzeko"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Kokapena"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"Atzitu gailuaren kokapena"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"gailuaren kokapena atzitzeko"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Egutegia"</string> - <string name="permgroupdesc_calendar" msgid="3889615280211184106">"Atzitu egutegia"</string> + <string name="permgroupdesc_calendar" msgid="3889615280211184106">"egutegia atzitzeko"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS mezuak"</string> - <string name="permgroupdesc_sms" msgid="4656988620100940350">"Bidali eta ikusi SMS mezuak"</string> + <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS mezuak bidaltzeko eta ikusteko"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Memoria"</string> - <string name="permgroupdesc_storage" msgid="637758554581589203">"Atzitu gailuko argazkiak, multimedia-elementuak eta fitxategiak"</string> + <string name="permgroupdesc_storage" msgid="637758554581589203">"gailuko argazkiak, multimedia-elementuak eta fitxategiak atzitzeko"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofonoa"</string> - <string name="permgroupdesc_microphone" msgid="4988812113943554584">"Grabatu audioa"</string> + <string name="permgroupdesc_microphone" msgid="4988812113943554584">"audioa grabatzeko"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"Atera argazkiak eta grabatu bideoak"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"argazkiak ateratzeko eta bideoak grabatzeko"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefonoa"</string> - <string name="permgroupdesc_phone" msgid="6234224354060641055">"Egin eta kudeatu telefono-deiak"</string> + <string name="permgroupdesc_phone" msgid="6234224354060641055">"telefono-deiak egiteko eta kudeatzeko"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Gorputz-sentsoreak"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"Atzitu bizi-konstanteei buruzko sentsore-datuak"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"bizi-konstanteei buruzko sentsore-datuak atzitzeko"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Eskuratu leihoko edukia"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Arakatu irekita daukazun leihoko edukia."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktibatu ukipen bidez arakatzeko eginbidea"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 6c031593e156..45d9dc36adae 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -144,14 +144,14 @@ <string name="httpErrorOk" msgid="1191919378083472204">"تأیید"</string> <string name="httpError" msgid="7956392511146698522">"خطایی در شبکه وجود داشت."</string> <string name="httpErrorLookup" msgid="4711687456111963163">"URL پیدا نشد."</string> - <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"طرح کلی تأیید اعتبار سایت پشتیبانی نمیشود."</string> + <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"طرح کلی تأیید اعتبار سایت پشتیبانی نمیشود."</string> <string name="httpErrorAuth" msgid="1435065629438044534">"تأیید اعتبار انجام نشد."</string> <string name="httpErrorProxyAuth" msgid="1788207010559081331">"تأیید اعتبار از طریق سرور پروکسی انجام نشد."</string> <string name="httpErrorConnect" msgid="8714273236364640549">"اتصال به سرور انجام نشد."</string> <string name="httpErrorIO" msgid="2340558197489302188">"برقراری ارتباط با سرور ممکن نبود. بعداً دوباره امتحان کنید."</string> <string name="httpErrorTimeout" msgid="4743403703762883954">"زمان اتصال به سرور تمام شده است."</string> <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"این صفحه دارای تعداد بسیار زیادی تغییر مسیر سرور است."</string> - <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"پروتکل پشتیبانی نمیشود."</string> + <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"پروتکل پشتیبانی نمیشود."</string> <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"اتصال امن ایجاد نشد."</string> <string name="httpErrorBadUrl" msgid="3636929722728881972">"بدلیل نامعتبر بودن URL، باز کردن صفحه ممکن نیست."</string> <string name="httpErrorFile" msgid="2170788515052558676">"دسترسی به فایل انجام نشد."</string> @@ -781,13 +781,13 @@ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"به برنامه اجازه میدهد تا سابقه یا نشانکهای ذخیره شده مرورگر در تلویزیون شما را تغییر دهد. شاید به برنامه اجازه دهد تا دادههای «مرورگر» را پاک کند یا تغییر دهد. توجه: این مجوز شاید توسط مرورگرهای شخص ثالث یا سایر برنامهها با قابلیتهای مرور وب اجرا شود."</string> <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"به برنامه اجازه میدهد سابقه مرورگر یا نشانکهای ذخیره شده در تلفن شما را اصلاح کند. این ویژگی ممکن است به برنامه اجازه دهد دادههای مرورگر را حذف یا اصلاح کند. توجه: این مجوز ممکن است توسط مرورگرهای شخص ثالث یا سایر برنامههای دارای قابلیت مرور وب قابل اجرا نباشد."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"تنظیم یک هشدار"</string> - <string name="permdesc_setAlarm" msgid="316392039157473848">"به برنامه اجازه میدهد تا هشداری را در برنامه ساعت زنگدار نصب شده تنظیم کند. برخی از برنامههای ساعت زنگدار نمیتوانند این ویژگی را اعمال کنند."</string> + <string name="permdesc_setAlarm" msgid="316392039157473848">"به برنامه اجازه میدهد تا هشداری را در برنامه ساعت زنگدار نصب شده تنظیم کند. برخی از برنامههای ساعت زنگدار نمیتوانند این ویژگی را اعمال کنند."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"افزودن پست صوتی"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"به برنامه اجازه میدهد تا پیامها را به صندوق دریافت پست صوتی شما اضافه کند."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"تغییر مجوزهای مکان جغرافیایی مرورگر"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"به برنامه اجازه میدهد تا مجوزهای جغرافیایی مرورگر را تغییر دهد. برنامههای مخرب میتوانند از آن استفاده کنند تا اطلاعات موقعیت مکانی را به سایتهای وب کتابخانه بفرستند."</string> <string name="save_password_message" msgid="767344687139195790">"میخواهید مرورگر این رمز ورود را به خاطر داشته باشد؟"</string> - <string name="save_password_notnow" msgid="6389675316706699758">"الآن نه"</string> + <string name="save_password_notnow" msgid="6389675316706699758">"اکنون نه"</string> <string name="save_password_remember" msgid="6491879678996749466">"به خاطر سپردن"</string> <string name="save_password_never" msgid="8274330296785855105">"هیچوقت"</string> <string name="open_permission_deny" msgid="7374036708316629800">"شما اجازه بازکردن این صفحه را ندارید."</string> @@ -894,16 +894,16 @@ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"پیشفرض را در تنظیمات سیستم> برنامهها> مورد دانلود شده پاک کنید."</string> <string name="chooseActivity" msgid="7486876147751803333">"انتخاب عملکرد"</string> <string name="chooseUsbActivity" msgid="6894748416073583509">"انتخاب برنامه برای دستگاه USB"</string> - <string name="noApplications" msgid="2991814273936504689">"هیچ برنامهای نمیتواند این کار را انجام دهد."</string> + <string name="noApplications" msgid="2991814273936504689">"هیچ برنامهای نمیتواند این کار را انجام دهد."</string> <string name="aerr_title" msgid="1905800560317137752"></string> <string name="aerr_application" msgid="932628488013092776">"متأسفانه، <xliff:g id="APPLICATION">%1$s</xliff:g> متوقف شده است."</string> <string name="aerr_process" msgid="4507058997035697579">"متأسفانه، پردازش <xliff:g id="PROCESS">%1$s</xliff:g> متوقف شده است."</string> <string name="aerr_process_silence" msgid="4226685530196000222">"تا راهاندازی مجدد، خرابیها از <xliff:g id="PROCESS">%1$s</xliff:g> نادیده گرفته شوند."</string> <string name="anr_title" msgid="4351948481459135709"></string> - <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> پاسخ نمیدهد.\n\nآیا میخواهید آنرا ببندید؟"</string> - <string name="anr_activity_process" msgid="5776209883299089767">"فعالیت <xliff:g id="ACTIVITY">%1$s</xliff:g> پاسخ نمیدهد.\n\nآیا میخواهید آن را ببندید؟"</string> - <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> پاسخ نمیدهد. آیا میخواهید آن را ببندید؟"</string> - <string name="anr_process" msgid="6513209874880517125">"روند <xliff:g id="PROCESS">%1$s</xliff:g> پاسخ نمیدهد. \n\nآیا میخواهید آن را ببندید؟"</string> + <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> پاسخ نمیدهد.\n\nآیا میخواهید آنرا ببندید؟"</string> + <string name="anr_activity_process" msgid="5776209883299089767">"فعالیت <xliff:g id="ACTIVITY">%1$s</xliff:g> پاسخ نمیدهد.\n\nآیا میخواهید آن را ببندید؟"</string> + <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> پاسخ نمیدهد. آیا میخواهید آن را ببندید؟"</string> + <string name="anr_process" msgid="6513209874880517125">"روند <xliff:g id="PROCESS">%1$s</xliff:g> پاسخ نمیدهد. \n\nآیا میخواهید آن را ببندید؟"</string> <string name="force_close" msgid="8346072094521265605">"تأیید"</string> <string name="report" msgid="4060218260984795706">"گزارش"</string> <string name="wait" msgid="7147118217226317732">"منتظر بمانید"</string> @@ -1006,14 +1006,14 @@ <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"همیشه غیرمجاز"</string> <string name="sim_removed_title" msgid="6227712319223226185">"سیم کارت برداشته شد"</string> <string name="sim_removed_message" msgid="5450336489923274918">"تا زمانی که با یک سیمکارت معتبر دوباره راهاندازی نکنید شبکه تلفن همراه غیر قابل دسترس خواهد بود."</string> - <string name="sim_done_button" msgid="827949989369963775">"انجام شد"</string> + <string name="sim_done_button" msgid="827949989369963775">"تمام"</string> <string name="sim_added_title" msgid="3719670512889674693">"سیم کارت اضافه شد"</string> <string name="sim_added_message" msgid="7797975656153714319">"برای دسترسی به شبکه تلفن همراه، دستگاهتان را مجدداً راهاندازی کنید."</string> <string name="sim_restart_button" msgid="4722407842815232347">"راهاندازی مجدد"</string> <string name="time_picker_dialog_title" msgid="8349362623068819295">"تنظیم زمان"</string> <string name="date_picker_dialog_title" msgid="5879450659453782278">"تاریخ تنظیم"</string> <string name="date_time_set" msgid="5777075614321087758">"تنظیم"</string> - <string name="date_time_done" msgid="2507683751759308828">"انجام شد"</string> + <string name="date_time_done" msgid="2507683751759308828">"تمام"</string> <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"جدید: "</font></string> <string name="perms_description_app" msgid="5139836143293299417">"ارائه شده توسط <xliff:g id="APP_NAME">%1$s</xliff:g> ."</string> <string name="no_permissions" msgid="7283357728219338112">"مجوزی لازم نیست"</string> @@ -1085,7 +1085,7 @@ <string name="ime_action_search" msgid="658110271822807811">"جستجو"</string> <string name="ime_action_send" msgid="2316166556349314424">"ارسال"</string> <string name="ime_action_next" msgid="3138843904009813834">"بعدی"</string> - <string name="ime_action_done" msgid="8971516117910934605">"انجام شد"</string> + <string name="ime_action_done" msgid="8971516117910934605">"تمام"</string> <string name="ime_action_previous" msgid="1443550039250105948">"قبلی"</string> <string name="ime_action_default" msgid="2840921885558045721">"اجرا کردن"</string> <string name="dial_number_using" msgid="5789176425167573586">"شماره گیری \nبا استفاده از <xliff:g id="NUMBER">%s</xliff:g>"</string> @@ -1131,7 +1131,7 @@ <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g></item> <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g></item> </plurals> - <string name="action_mode_done" msgid="7217581640461922289">"انجام شد"</string> + <string name="action_mode_done" msgid="7217581640461922289">"تمام"</string> <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"در حال پاک کردن حافظهٔ USB..."</string> <string name="progress_erasing" product="default" msgid="6596988875507043042">"در حال پاک کردن کارت SD..."</string> <string name="share" msgid="1778686618230011964">"اشتراکگذاری"</string> @@ -1173,7 +1173,7 @@ <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> - <string name="keyboardview_keycode_done" msgid="1992571118466679775">"انجام شد"</string> + <string name="keyboardview_keycode_done" msgid="1992571118466679775">"تمام"</string> <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"تغییر حالت"</string> <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string> <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string> @@ -1416,7 +1416,7 @@ <string name="immersive_cling_title" msgid="8394201622932303336">"مشاهده در حالت تمام صفحه"</string> <string name="immersive_cling_description" msgid="3482371193207536040">"برای خروج، انگشتتان را از بالای صفحه به پایین بکشید."</string> <string name="immersive_cling_positive" msgid="5016839404568297683">"متوجه شدم"</string> - <string name="done_label" msgid="2093726099505892398">"انجام شد"</string> + <string name="done_label" msgid="2093726099505892398">"تمام"</string> <string name="hour_picker_description" msgid="6698199186859736512">"لغزنده دایرهای ساعت"</string> <string name="minute_picker_description" msgid="8606010966873791190">"لغزنده دایرهای دقیقه"</string> <string name="select_hours" msgid="6043079511766008245">"انتخاب ساعت"</string> diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index 7b5ca2949fb9..c32add03c72f 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -229,7 +229,7 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder aos teus contactos"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Localización"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"acceso á localización deste dispositivo"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"acceder á localización deste dispositivo"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceder ao teu calendario"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml index 939299779f29..6281abf705b4 100644 --- a/core/res/res/values-gu-rIN/strings.xml +++ b/core/res/res/values-gu-rIN/strings.xml @@ -229,8 +229,8 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"સંપર્કો"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"તમારા સંપર્કોને ઍક્સેસ કરો"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"સ્થાન"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરો"</string> - <string name="permgrouplab_calendar" msgid="5863508437783683902">"કૅલેન્ડર"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની"</string> + <string name="permgrouplab_calendar" msgid="5863508437783683902">"કેલેન્ડર"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"તમારા કેલેન્ડરને ઍક્સેસ કરવાની"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS સંદેશા મોકલો અને જોવાની"</string> @@ -326,14 +326,14 @@ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"એપ્લિકેશનને ઇનકમિંગ અને આઉટગોઇંગ કૉલ્સ વિશેનાં ડેટા સહિત, તમારા ફોનના કૉલ લૉગને સંશોધિત કરવાની મંજૂરી આપે છે. દુર્ભાવનાપૂર્ણ એપ્લિકેશનો આનો ઉપયોગ તમારા કૉલ લૉગને કાઢી નાખવા અથવા સંશોધિત માટે કરી શકે છે."</string> <string name="permlab_bodySensors" msgid="4871091374767171066">"બૉડી સેન્સર્સ (જેમ કે હાર્ટ રેટ મૉનિટર્સ)"</string> <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"એપ્લિકેશનને તમારી હૃદય ગતિ જેવી તમારી શારીરિક સ્થિતિને મૉનિટર કરતાં સેન્સર્સથી ડેટા ઍક્સેસ કરવાની મંજૂરી આપે છે."</string> - <string name="permlab_readCalendar" msgid="5972727560257612398">"કૅલેન્ડર ઇવેન્ટ્સ વત્તા ગોપનીયતા માહિતી વાંચો"</string> - <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર સંગ્રહિત તમામ કૅલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કૅલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string> - <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર સંગ્રહિત તમામ કૅલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કૅલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string> - <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર સંગ્રહિત તમામ કૅલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કૅલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string> - <string name="permlab_writeCalendar" msgid="8438874755193825647">"કૅલેન્ડર ઇવેન્ટ્સ ઉમેરો અથવા સંશોધિત કરો અને માલિકની જાણ બહાર અતિથિઓને ઇમેઇલ મોકલો"</string> - <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કૅલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string> - <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કૅલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string> - <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કૅલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string> + <string name="permlab_readCalendar" msgid="5972727560257612398">"કેલેન્ડર ઇવેન્ટ્સ વત્તા ગોપનીયતા માહિતી વાંચો"</string> + <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર સંગ્રહિત તમામ કેલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કેલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string> + <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર સંગ્રહિત તમામ કેલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કેલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string> + <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર સંગ્રહિત તમામ કેલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કેલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string> + <string name="permlab_writeCalendar" msgid="8438874755193825647">"કેલેન્ડર ઇવેન્ટ્સ ઉમેરો અથવા સંશોધિત કરો અને માલિકની જાણ બહાર અતિથિઓને ઇમેઇલ મોકલો"</string> + <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કેલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string> + <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કેલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string> + <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કેલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string> <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"વધારાના સ્થાન પ્રદાતા આદેશોને ઍક્સેસ કરો"</string> <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"એપ્લિકેશનને વધારાના સ્થાન પ્રદાતા આદેશોને ઍક્સેસ કરવાની મંજૂરી આપે છે. આ એપ્લિકેશનને GPS અથવા અન્ય સ્થાન સ્રોતોના ઓપરેશનમાં દખલ કરવાની મંજૂરી આપી શકે છે."</string> <string name="permlab_accessFineLocation" msgid="1191898061965273372">"નિશ્ચિત સ્થાન (GPS અને નેટવર્ક-આધારિત)"</string> diff --git a/core/res/res/values-it-watch/strings.xml b/core/res/res/values-it-watch/strings.xml index c348e481cd7e..aa6a4be8f64c 100644 --- a/core/res/res/values-it-watch/strings.xml +++ b/core/res/res/values-it-watch/strings.xml @@ -29,7 +29,7 @@ <string name="permgrouplab_storagewear" msgid="1003807594193602313">"accedere a foto, contenuti multimediali e file sull\'orologio"</string> <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"registrare audio"</string> <string name="permgrouplab_camerawear" msgid="4543951283103407017">"scattare foto e registrare video"</string> - <string name="permgrouplab_phonewear" msgid="134365036753766126">"fare e gestire telefonate"</string> + <string name="permgrouplab_phonewear" msgid="134365036753766126">"eseguire e gestire le telefonate"</string> <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"accedere ai dati dei sensori relativi ai tuoi parametri vitali"</string> <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"avere la funzione di barra di stato"</string> <string name="permlab_bodySensorswear" msgid="7857941041202791873">"accedere ai sensori (come il cardiofrequenzimetro)"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 42712876b15d..72b1c54293d6 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -239,11 +239,11 @@ <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfono"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"registrare audio"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotocamera"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"acquisire foto e registrare video"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"scattare foto e registrare video"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefono"</string> <string name="permgroupdesc_phone" msgid="6234224354060641055">"eseguire e gestire le telefonate"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensori per il corpo"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accedere ai dati dei sensori sui tuoi parametri vitali"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accedere ai dati dei sensori relativi ai tuoi parametri vitali"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperare contenuti della finestra"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Esaminare i contenuti di una finestra con cui interagisci."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Attivare Esplora al tocco"</string> @@ -272,7 +272,7 @@ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Consente all\'applicazione di leggere i messaggi cell broadcast ricevuti dal dispositivo. Gli avvisi cell broadcast vengono trasmessi in alcune località per avvertire di eventuali situazioni di emergenza. Le applicazioni dannose potrebbero interferire con il rendimento o con il funzionamento del dispositivo quando si riceve un messaggio cell broadcast di emergenza."</string> <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lettura feed sottoscritti"</string> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Consente all\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string> - <string name="permlab_sendSms" msgid="7544599214260982981">"invio e lettura di SMS"</string> + <string name="permlab_sendSms" msgid="7544599214260982981">"inviare e visualizzare SMS"</string> <string name="permdesc_sendSms" msgid="7094729298204937667">"Consente all\'applicazione di inviare messaggi SMS. Ciò potrebbe comportare costi imprevisti. Applicazioni dannose potrebbero generare dei costi inviando messaggi senza la tua conferma."</string> <string name="permlab_readSms" msgid="8745086572213270480">"lettura messaggi di testo personali (SMS o MMS)"</string> <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Consente all\'applicazione di leggere i messaggi SMS memorizzati sul tablet o sulla scheda SIM. Ciò consente all\'applicazione di leggere tutti i messaggi SMS, indipendentemente dai contenuti o dal livello di riservatezza."</string> @@ -342,7 +342,7 @@ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Consente all\'applicazione di ottenere la tua posizione approssimativa. Questa posizione viene ottenuta da servizi di localizzazione utilizzando fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione approssimativa."</string> <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifica impostazioni audio"</string> <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Consente all\'applicazione di modificare le impostazioni audio globali, come il volume e quale altoparlante viene utilizzato per l\'uscita."</string> - <string name="permlab_recordAudio" msgid="3876049771427466323">"registrazione audio"</string> + <string name="permlab_recordAudio" msgid="3876049771427466323">"registrare audio"</string> <string name="permdesc_recordAudio" msgid="4906839301087980680">"Consente all\'applicazione di registrare audio con il microfono. Questa autorizzazione consente all\'applicazione di registrare audio in qualsiasi momento senza la tua conferma."</string> <string name="permlab_sim_communication" msgid="1180265879464893029">"comunicazione SIM"</string> <string name="permdesc_sim_communication" msgid="5725159654279639498">"Consente all\'app di inviare comandi alla SIM. Questo è molto pericoloso."</string> diff --git a/core/res/res/values-ja-watch/strings.xml b/core/res/res/values-ja-watch/strings.xml index 3248041becd3..82c3ffdb8a1a 100644 --- a/core/res/res/values-ja-watch/strings.xml +++ b/core/res/res/values-ja-watch/strings.xml @@ -37,7 +37,7 @@ <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"おおよその位置情報(ネットワーク基地局)へのアクセス"</string> <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIMへのコマンド送信"</string> <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ネットワークへのフルアクセス"</string> - <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"プロフィールの所有者と端末の所有者の管理"</string> + <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"プロファイルの所有者と端末の所有者の管理"</string> <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX状態の変更"</string> <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Androidビーム転送のステータスの受信"</string> <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"メディア出力のルーティング"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 545b963cef61..135c7ea9157c 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -282,8 +282,8 @@ <string name="permdesc_receiveWapPush" msgid="748232190220583385">"WAPメッセージの受信と処理をアプリに許可します。これにより、アプリが端末に届いたメッセージを表示することなく監視または削除できるようになります。"</string> <string name="permlab_getTasks" msgid="6466095396623933906">"実行中のアプリの取得"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"現在実行中または最近実行したタスクに関する情報の取得をアプリに許可します。これにより、その端末でどのアプリを使用しているかをアプリから識別できるようになる可能性があります。"</string> - <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"プロフィールの所有者と端末の所有者の管理"</string> - <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"プロフィールの所有者と端末の所有者の設定をアプリに許可します。"</string> + <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"プロファイルの所有者と端末の所有者の管理"</string> + <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"プロファイルの所有者と端末の所有者の設定をアプリに許可します。"</string> <string name="permlab_reorderTasks" msgid="2018575526934422779">"実行中のアプリの順序変更"</string> <string name="permdesc_reorderTasks" msgid="7734217754877439351">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリに許可します。これにより、アプリがユーザーからの入力なしでこの処理を実行する可能性があります。"</string> <string name="permlab_enableCarMode" msgid="5684504058192921098">"運転モードの有効化"</string> diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml index d39ee056c709..7af4df041821 100644 --- a/core/res/res/values-kk-rKZ/strings.xml +++ b/core/res/res/values-kk-rKZ/strings.xml @@ -229,7 +229,7 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контактілер"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"контактілерге кіру"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Орын"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"бұл құрылғының орнына кіру"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"бұл құрылғының орналасқан жерін көру"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Күнтізбе"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"күнтізбеге кіру"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml index e7e43f0ebcd9..f20551dcf067 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -229,7 +229,7 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"Байланыштар"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"байланыштарыңызга уруксат"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Жайгашкан жер"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"бул түзмөктүн жайгашкан жерине кирүү"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"бул түзмөктүн жайгашкан жери тууралуу дайындарды көрүү"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Күнбарак"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"жылнаамаңызды пайдалануу"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml index f10fb1907cd2..a41be56b7637 100644 --- a/core/res/res/values-mk-rMK/strings.xml +++ b/core/res/res/values-mk-rMK/strings.xml @@ -227,23 +227,23 @@ <string name="user_owner_label" msgid="2804351898001038951">"Лични"</string> <string name="managed_profile_label" msgid="6260850669674791528">"Работа"</string> <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string> - <string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапи до контактите"</string> + <string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапува до контактите"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"да пристапува до локацијата на овој уред"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"пристапува до локацијата на овој уред"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string> - <string name="permgroupdesc_calendar" msgid="3889615280211184106">"пристапи до календарот"</string> + <string name="permgroupdesc_calendar" msgid="3889615280211184106">"пристапува до календарот"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"СМС"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"испраќа и прикажува СМС-пораки"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Меморија"</string> - <string name="permgroupdesc_storage" msgid="637758554581589203">"пристапува до фотографии, медиуми и датотеки на уредот"</string> + <string name="permgroupdesc_storage" msgid="637758554581589203">"пристапува до фотографии, аудио-видео и датотеки на уредот"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string> - <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снимај аудио"</string> + <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Фотоапарат"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"фотографирај и снимај видео"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"фотографира и снима видео"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string> - <string name="permgroupdesc_phone" msgid="6234224354060641055">"повикувај и управувај со телефонски повици"</string> + <string name="permgroupdesc_phone" msgid="6234224354060641055">"упатува и управува со телефонски повици"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Телесни сензори"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"пристапи до податоците од сензорите за виталните знаци"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"пристапува до податоците од сензорите за виталните знаци"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Врати содржина на прозорец"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Провери ја содржината на прозорецот со кој се комуницира."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Вклучи „Истражувај со допир“"</string> diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml index a547ca733ca6..41528d87cbca 100644 --- a/core/res/res/values-my-rMM/strings.xml +++ b/core/res/res/values-my-rMM/strings.xml @@ -229,7 +229,7 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"အဆက်အသွယ်များ"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"သင့် အဆက်အသွယ်များအား ဝင်ရောက်သုံးရန်"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"တည်နေရာ"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"စက်ပစ္စည်း၏ တည်နေရာကို အသုံးပြုမည်"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"ဤစက်ပစ္စည်း၏ တည်နေရာကို ရယူ"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"ပြက္ခဒိန်"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"သင့်ပြက္ခဒိန်အား ဝင်ရောက်သုံးရန်"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"စာတိုစနစ်"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index d203a6a6c86f..2f6c8bf173ae 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -227,23 +227,23 @@ <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string> <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string> <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string> - <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acessar seus contatos"</string> + <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string> <string name="permgroupdesc_location" msgid="1346617465127855033">"acesse o local do dispositivo"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string> - <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acessar sua agenda"</string> + <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string> - <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do seu dispositivo"</string> + <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"grave áudio"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Câmera"</string> <string name="permgroupdesc_camera" msgid="3250611594678347720">"tire fotos e grave vídeos"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefone"</string> - <string name="permgroupdesc_phone" msgid="6234224354060641055">"fazer e gerenciar chamadas telefônicas"</string> + <string name="permgroupdesc_phone" msgid="6234224354060641055">"faça e gerencie chamadas telefônicas"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporais"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acessar dados do sensor sobre seus sinais vitais"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acesse dados do sensor sobre seus sinais vitais"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar cont. da janela"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecionar o conteúdo da janela com que você está interagindo."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Ativar Explorar por toque"</string> @@ -272,7 +272,7 @@ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string> <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds inscritos"</string> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite que o app obtenha detalhes sobre os feeds sincronizados no momento."</string> - <string name="permlab_sendSms" msgid="7544599214260982981">"enviar e ver mensagens SMS"</string> + <string name="permlab_sendSms" msgid="7544599214260982981">"envie e veja mensagens SMS"</string> <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite que o app envie mensagens SMS. Isso pode resultar em cobranças inesperadas. Apps maliciosos podem gerar custos através do envio de mensagens sem sua confirmação."</string> <string name="permlab_readSms" msgid="8745086572213270480">"ler suas mensagens de texto (SMS ou MMS)"</string> <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite que o app leia mensagens SMS armazenadas no tablet ou cartão SIM. Isso permite que o app leia todas as mensagens SMS, independentemente de seu conteúdo ou confidencialidade."</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index d203a6a6c86f..2f6c8bf173ae 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -227,23 +227,23 @@ <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string> <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string> <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string> - <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acessar seus contatos"</string> + <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string> <string name="permgroupdesc_location" msgid="1346617465127855033">"acesse o local do dispositivo"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string> - <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acessar sua agenda"</string> + <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string> - <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do seu dispositivo"</string> + <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"grave áudio"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Câmera"</string> <string name="permgroupdesc_camera" msgid="3250611594678347720">"tire fotos e grave vídeos"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefone"</string> - <string name="permgroupdesc_phone" msgid="6234224354060641055">"fazer e gerenciar chamadas telefônicas"</string> + <string name="permgroupdesc_phone" msgid="6234224354060641055">"faça e gerencie chamadas telefônicas"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporais"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acessar dados do sensor sobre seus sinais vitais"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acesse dados do sensor sobre seus sinais vitais"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar cont. da janela"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecionar o conteúdo da janela com que você está interagindo."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Ativar Explorar por toque"</string> @@ -272,7 +272,7 @@ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string> <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds inscritos"</string> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite que o app obtenha detalhes sobre os feeds sincronizados no momento."</string> - <string name="permlab_sendSms" msgid="7544599214260982981">"enviar e ver mensagens SMS"</string> + <string name="permlab_sendSms" msgid="7544599214260982981">"envie e veja mensagens SMS"</string> <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite que o app envie mensagens SMS. Isso pode resultar em cobranças inesperadas. Apps maliciosos podem gerar custos através do envio de mensagens sem sua confirmação."</string> <string name="permlab_readSms" msgid="8745086572213270480">"ler suas mensagens de texto (SMS ou MMS)"</string> <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite que o app leia mensagens SMS armazenadas no tablet ou cartão SIM. Isso permite que o app leia todas as mensagens SMS, independentemente de seu conteúdo ou confidencialidade."</string> diff --git a/core/res/res/values-ro-watch/strings.xml b/core/res/res/values-ro-watch/strings.xml index e412cad4f674..9a8e4e0f4857 100644 --- a/core/res/res/values-ro-watch/strings.xml +++ b/core/res/res/values-ro-watch/strings.xml @@ -22,15 +22,15 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplic. <xliff:g id="NUMBER_0">%1$d</xliff:g> din <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string> <string name="permgrouplab_sensors" msgid="202675452368612754">"Senzori"</string> - <string name="permgrouplab_contactswear" msgid="2340286500790908344">"să acceseze persoanele de contact"</string> + <string name="permgrouplab_contactswear" msgid="2340286500790908344">"acceseze persoanele de contact"</string> <string name="permgrouplab_locationwear" msgid="6275317222482780209">"să acceseze locația acestui ceas"</string> - <string name="permgrouplab_calendarwear" msgid="441900844045065081">"să acceseze calendarul"</string> - <string name="permgrouplab_smswear" msgid="6849506550342974220">"să trimită și să vadă mesajele SMS"</string> + <string name="permgrouplab_calendarwear" msgid="441900844045065081">"acceseze calendarul"</string> + <string name="permgrouplab_smswear" msgid="6849506550342974220">"trimită și să vadă mesajele SMS"</string> <string name="permgrouplab_storagewear" msgid="1003807594193602313">"să acceseze fotografiile, conținutul media și fișierele de pe ceas"</string> - <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"să înregistreze conținut audio"</string> - <string name="permgrouplab_camerawear" msgid="4543951283103407017">"să fotografieze și să înregistreze videoclipuri"</string> - <string name="permgrouplab_phonewear" msgid="134365036753766126">"să inițieze să și gestioneze apeluri telefonice"</string> - <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"să acceseze datele de la senzori despre semnele vitale"</string> + <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"înregistreze sunet"</string> + <string name="permgrouplab_camerawear" msgid="4543951283103407017">"fotografieze și să înregistreze imagini"</string> + <string name="permgrouplab_phonewear" msgid="134365036753766126">"inițieze să și gestioneze apeluri telefonice"</string> + <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"acceseze datele de la senzori despre semnele vitale"</string> <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"să fie bara de stare"</string> <string name="permlab_bodySensorswear" msgid="7857941041202791873">"să acceseze senzorii corporali (cum ar fi monitoarele cardiace)"</string> <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"să acceseze locația exactă (bazată pe GPS și pe rețea)"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index d215d4c3d7a7..5062e7628b6d 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -135,7 +135,7 @@ <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Se preferă conexiunea Wi-Fi"</string> <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Se preferă conexiunea mobilă"</string> <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Numai Wi-Fi"</string> - <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionată"</string> + <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecționată"</string> <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string> <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> după <xliff:g id="TIME_DELAY">{2}</xliff:g> (de) secunde"</string> <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionat"</string> @@ -232,19 +232,19 @@ <string name="permgrouplab_location" msgid="7275582855722310164">"Locație"</string> <string name="permgroupdesc_location" msgid="1346617465127855033">"acceseze locația acestui dispozitiv"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendar"</string> - <string name="permgroupdesc_calendar" msgid="3889615280211184106">"accesează calendarul"</string> + <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceseze calendarul"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> - <string name="permgroupdesc_sms" msgid="4656988620100940350">"trimite și vede mesajele SMS"</string> + <string name="permgroupdesc_sms" msgid="4656988620100940350">"trimită și să vadă mesajele SMS"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Stocare"</string> <string name="permgroupdesc_storage" msgid="637758554581589203">"acceseze fotografiile, conținutul media și fișierele de pe dispozitiv"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfonul"</string> - <string name="permgroupdesc_microphone" msgid="4988812113943554584">"înregistreze conținut audio"</string> + <string name="permgroupdesc_microphone" msgid="4988812113943554584">"înregistreze sunet"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Camera foto"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"fotografieze și să înregistreze videoclipuri"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"fotografieze și să înregistreze imagini"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string> <string name="permgroupdesc_phone" msgid="6234224354060641055">"inițieze și să gestioneze apeluri telefonice"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori corporali"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accesează datele înregistrate de senzori despre semnele vitale"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceseze datele de la senzori despre semnele vitale"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperează conținutul ferestrei"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspectează conținutul unei ferestre cu care interacționați."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activează funcția Explorați prin atingere"</string> @@ -270,11 +270,11 @@ <string name="permlab_receiveMms" msgid="1821317344668257098">"primeşte mesaje text (MMS)"</string> <string name="permdesc_receiveMms" msgid="533019437263212260">"Permite aplicației să primească și să proceseze mesaje MMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string> <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"citeşte mesajele cu transmisie celulară"</string> - <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situaţiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanţa sau funcţionarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string> + <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situațiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanţa sau funcționarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string> <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"citire feeduri abonat"</string> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite aplicației să obţină detalii despre feedurile sincronizate în prezent."</string> - <string name="permlab_sendSms" msgid="7544599214260982981">"trimite și vede mesajele SMS"</string> - <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariţia unor taxe neaşteptate. Aplicaţiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string> + <string name="permlab_sendSms" msgid="7544599214260982981">"trimită și să vadă mesajele SMS"</string> + <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariția unor taxe neaşteptate. Aplicaţiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string> <string name="permlab_readSms" msgid="8745086572213270480">"citeşte mesajele text (SMS sau MMS)"</string> <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite aplicației să citească mesajele SMS stocate pe tabletă sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidenţialitate al acestora."</string> <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Permite aplicației să citească mesajele SMS stocate pe televizor sau pe cardul SIM. Cu această permisiune, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string> @@ -292,11 +292,11 @@ <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"închide alte aplicații"</string> <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Permite aplicației să oprească procesele derulate în fundal de alte aplicații. Acest lucru poate face ca respectivele aplicații să nu mai ruleze."</string> <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"suprapune elemente vizuale peste alte aplicații"</string> - <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite aplicației să suprapună elemente vizuale peste alte aplicații sau părţi ale interfeţei cu utilizatorul. Acestea pot interfera cu utilizarea de către dvs. a interfeţei în orice aplicație sau pot schimba ceea ce credeţi că vedeţi în alte aplicații."</string> + <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite aplicației să suprapună elemente vizuale peste alte aplicații sau părți ale interfeței cu utilizatorul. Acestea pot interfera cu utilizarea de către dvs. a interfeței în orice aplicație sau pot schimba ceea ce credeți că vedeţi în alte aplicații."</string> <string name="permlab_persistentActivity" msgid="8841113627955563938">"rulare continuă a aplicației"</string> - <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permite aplicației să declare persistente în memorie anumite părţi ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcţionarea tabletei."</string> + <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea tabletei."</string> <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea televizorului."</string> - <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permite aplicației să declare persistente în memorie anumite părţi ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcţionarea telefonului."</string> + <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea telefonului."</string> <string name="permlab_getPackageSize" msgid="7472921768357981986">"măsurare spaţiu de stocare al aplicației"</string> <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Permite aplicației să preia dimensiunile codului, ale datelor și ale memoriei cache"</string> <string name="permlab_writeSettings" msgid="2226195290955224730">"modifică setări de sistem"</string> @@ -310,17 +310,17 @@ <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze televizorul, determinându-l să utilizeze prea multă memorie."</string> <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze telefonul, determinându-l să utilizeze prea multă memorie."</string> <string name="permlab_readContacts" msgid="8348481131899886131">"citeşte agenda"</string> - <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără ştirea dvs."</string> + <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string> <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Permite aplicației să citească datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string> - <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără ştirea dvs."</string> + <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string> <string name="permlab_writeContacts" msgid="5107492086416793544">"modifică agenda"</string> - <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string> + <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string> <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Permite aplicației să modifice datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane de contact. Cu această permisiune, aplicația poate șterge datele de contact."</string> - <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string> + <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string> <string name="permlab_readCallLog" msgid="3478133184624102739">"citeşte jurnalul de apeluri"</string> - <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string> + <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string> <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Permite aplicației să citească jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune, aplicațiile pot să salveze datele din jurnalul de apeluri, iar aplicațiile rău-intenționate pot permite accesul la datele din jurnalul de apeluri fără cunoștința dvs."</string> - <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string> + <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string> <string name="permlab_writeCallLog" msgid="8552045664743499354">"scrie jurnalul de apeluri"</string> <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string> <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Permite aplicației să modifice jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău-intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul de apeluri."</string> @@ -331,10 +331,10 @@ <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Permite aplicației să citească toate evenimentele din calendar stocate pe tabletă, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string> <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Permite aplicației să citească toate evenimentele din calendar stocate pe televizor, inclusiv cele ale prietenilor sau colegilor. Cu această permisiune, aplicația poate să permită accesul la datele din calendar sau să le salveze, indiferent dacă acestea sunt confidențiale sau sensibile."</string> <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Permite aplicației să citească toate evenimentele din calendar stocate pe telefon, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string> - <string name="permlab_writeCalendar" msgid="8438874755193825647">"adăugarea sau modificarea evenimentelor din calendar și trimiterea de e-mailuri invitaţilor fără ştirea proprietarului"</string> - <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string> + <string name="permlab_writeCalendar" msgid="8438874755193825647">"adăugarea sau modificarea evenimentelor din calendar și trimiterea de e-mailuri invitaților fără știrea proprietarului"</string> + <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără știrea proprietarilor."</string> <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe televizor, inclusiv pe cele ale prietenilor sau ale colegilor. Cu această permisiune, aplicația poate să trimită mesaje care par că vin din partea proprietarilor calendarului sau să modifice evenimentele fără cunoștința acestora."</string> - <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe telefon, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string> + <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe telefon, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără știrea proprietarilor."</string> <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locației"</string> <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite aplicației să acceseze comenzi suplimentare pentru furnizorul locației. Aplicația ar putea să utilizeze această permisiune pentru a influența operațiile GPS sau ale altor surse de locații."</string> <string name="permlab_accessFineLocation" msgid="1191898061965273372">"locaţia exactă (bazată pe rețea și GPS)"</string> @@ -343,7 +343,7 @@ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite aplicației să obţină locaţia dvs. aproximativă. Această locație este dedusă de serviciile de localizare utilizând surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locaţia dvs. aproximativă."</string> <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modificare setări audio"</string> <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite aplicației să modifice setările audio globale, cum ar fi volumul și difuzorul care este utilizat pentru ieșire."</string> - <string name="permlab_recordAudio" msgid="3876049771427466323">"înregistrare audio"</string> + <string name="permlab_recordAudio" msgid="3876049771427466323">"înregistreze sunet"</string> <string name="permdesc_recordAudio" msgid="4906839301087980680">"Permite aplicației să efectueze înregistrări audio cu ajutorul microfonului. Cu această permisiune aplicația efectuează oricând înregistrări audio fără confirmare."</string> <string name="permlab_sim_communication" msgid="1180265879464893029">"comunicare cu cardul SIM"</string> <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permite aplicației să trimită comenzi pe cardul SIM. Această permisiune este foarte periculoasă."</string> @@ -354,11 +354,11 @@ <string name="permlab_flashlight" msgid="2155920810121984215">"control lanternă"</string> <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite aplicației să controleze lanterna."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string> - <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariţia unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string> + <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string> <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite aplicației să folosească serviciul IMS pentru apeluri, fără intervenția dvs."</string> <string name="permlab_readPhoneState" msgid="9178228524507610486">"citeşte starea și identitatea telefonului"</string> - <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicației să acceseze funcţiile de telefon ale dispozitivului. Cu această permisiune aplicația stabileşte numărul de telefon și ID-urile de dispozitiv, dacă un apel este activ, precum și numărul de la distanţă conectat printr-un apel."</string> + <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicației să acceseze funcţiile de telefon ale dispozitivului. Cu această permisiune aplicația stabilește numărul de telefon și ID-urile de dispozitiv, dacă un apel este activ, precum și numărul de la distanţă conectat printr-un apel."</string> <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string> <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"împiedică intrarea televizorului în stare de inactivitate"</string> <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string> @@ -756,7 +756,7 @@ <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Rămâneți în această pagină"</string> <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nSigur doriți să părăsiți această pagină?"</string> <string name="save_password_label" msgid="6860261758665825069">"Confirmați"</string> - <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriţi și micşoraţi prin dublă atingere."</string> + <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriți și micșorați prin dublă atingere."</string> <string name="autofill_this_form" msgid="4616758841157816676">"Automat"</string> <string name="setup_autofill" msgid="7103495070180590814">"Conf.Compl.auto."</string> <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string> @@ -767,7 +767,7 @@ <string name="autofill_postal_code" msgid="4696430407689377108">"Cod poştal"</string> <string name="autofill_state" msgid="6988894195520044613">"Stat"</string> <string name="autofill_zip_code" msgid="8697544592627322946">"Cod ZIP"</string> - <string name="autofill_county" msgid="237073771020362891">"Judeţ"</string> + <string name="autofill_county" msgid="237073771020362891">"Județ"</string> <string name="autofill_island" msgid="4020100875984667025">"Insulă"</string> <string name="autofill_district" msgid="8400735073392267672">"District"</string> <string name="autofill_department" msgid="5343279462564453309">"Departament"</string> @@ -776,11 +776,11 @@ <string name="autofill_area" msgid="3547409050889952423">"Zonă"</string> <string name="autofill_emirate" msgid="2893880978835698818">"Emirat"</string> <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"citeşte marcajele și istoricul web"</string> - <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string> + <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string> <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"scrie în marcajele și în istoricul web"</string> - <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string> + <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string> <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Permite aplicației să modifice istoricul sau marcajele browserului stocate pe televizor. Cu această permisiune, aplicația poate șterge sau modifica datele din browser. Notă: această permisiune nu poate fi aplicată de browsere terță parte sau de alte aplicații cu capacități de navigare pe web."</string> - <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string> + <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string> <string name="permlab_setAlarm" msgid="1379294556362091814">"setează o alarmă"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite aplicației să seteze o alarmă într-o aplicație de ceas cu alarmă instalată. Este posibil ca unele aplicații de ceas cu alarmă să nu implementeze această funcție."</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"adăugare mesagerie vocală"</string> @@ -803,11 +803,11 @@ <string name="searchview_description_search" msgid="6749826639098512120">"Căutați"</string> <string name="searchview_description_query" msgid="5911778593125355124">"Interogare de căutare"</string> <string name="searchview_description_clear" msgid="1330281990951833033">"Ștergeți interogarea"</string> - <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteţi interogarea"</string> + <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteți interogarea"</string> <string name="searchview_description_voice" msgid="2453203695674994440">"Căutare vocală"</string> - <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Exploraţi prin atingere?"</string> - <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu tableta."</string> - <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu telefonul."</string> + <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Explorați prin atingere?"</string> + <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu tableta."</string> + <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu telefonul."</string> <string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string> <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string> <plurals name="last_num_days" formatted="false" msgid="5104533550723932025"> @@ -918,7 +918,7 @@ <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string> <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string> <string name="screen_compat_mode_show" msgid="4013878876486655892">"Afişaţi întotdeauna"</string> - <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivaţi acest mod din Setări de sistem > Aplicații > Descărcate."</string> + <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem > Aplicații > Descărcate."</string> <string name="smv_application" msgid="3307209192155442829">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string> <string name="smv_process" msgid="5120397012047462446">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> a încălcat propria politică StrictMode."</string> <string name="android_upgrading_title" msgid="1584192285441405746">"Android trece la o versiune superioară..."</string> @@ -1002,10 +1002,10 @@ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> trimite un număr mare de mesaje SMS. Permiteți acestei aplicații să trimită în continuare mesaje?"</string> <string name="sms_control_yes" msgid="3663725993855816807">"Permiteți"</string> <string name="sms_control_no" msgid="625438561395534982">"Refuzaţi"</string> - <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> intenţionează să trimită un mesaj la <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string> + <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> intenționează să trimită un mesaj la <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string> <string name="sms_short_code_details" msgid="5873295990846059400">"Acest lucru "<b>"poate genera costuri"</b>" în contul dvs. mobil."</string> <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Acest lucru va genera costuri în contul dvs. mobil."</b></string> - <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Trimiteţi"</string> + <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Trimiteți"</string> <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Anulați"</string> <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Doresc să se reţină opţiunea"</string> <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puteți modifica ulterior în Setări > Aplicații"</string> @@ -1080,8 +1080,8 @@ <string name="ext_media_status_formatting" msgid="1085079556538644861">"Se formatează…"</string> <string name="ext_media_status_missing" msgid="5638633895221670766">"Nu este introdus"</string> <string name="activity_list_empty" msgid="1675388330786841066">"Nu s-a găsit nicio activitate potrivită."</string> - <string name="permlab_route_media_output" msgid="1642024455750414694">"Direcţionează rezultatele media"</string> - <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite unei aplicații să direcţioneze rezultate media către alte dispozitive externe."</string> + <string name="permlab_route_media_output" msgid="1642024455750414694">"Direcționează rezultatele media"</string> + <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite unei aplicații să direcționeze rezultate media către alte dispozitive externe."</string> <string name="permlab_readInstallSessions" msgid="6165432407628065939">"Citirea sesiunilor de instalare"</string> <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite unei aplicații accesul la citirea sesiunilor de instalare. Aceasta poate vedea detalii despre instalările de pachete active."</string> <string name="permlab_requestInstallPackages" msgid="1772330282283082214">"Solicită instalarea pachetelor"</string> @@ -1124,7 +1124,7 @@ <string name="upload_file" msgid="2897957172366730416">"Alegeţi un fişier"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string> <string name="reset" msgid="2448168080964209908">"Resetaţi"</string> - <string name="submit" msgid="1602335572089911941">"Trimiteţi"</string> + <string name="submit" msgid="1602335572089911941">"Trimiteți"</string> <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mod Maşină activat"</string> <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Atingeți pentru a ieşi din modul Maşină."</string> <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering sau hotspot activ"</string> @@ -1160,21 +1160,21 @@ <string name="choose_account_label" msgid="5655203089746423927">"Alegeţi un cont"</string> <string name="add_account_label" msgid="2935267344849993553">"Adăugaţi un cont"</string> <string name="add_account_button_label" msgid="3611982894853435874">"Adăugaţi un cont"</string> - <string name="number_picker_increment_button" msgid="2412072272832284313">"Creşteţi"</string> + <string name="number_picker_increment_button" msgid="2412072272832284313">"Creșteți"</string> <string name="number_picker_decrement_button" msgid="476050778386779067">"Reduceţi"</string> <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Atingeți și țineți apăsat <xliff:g id="VALUE">%s</xliff:g>."</string> <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Glisaţi în sus pentru a creşte și în jos pentru a reduce."</string> - <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Creşteţi valoarea pentru minute"</string> + <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Creșteți valoarea pentru minute"</string> <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Reduceţi valoarea pentru minute"</string> - <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Creşteţi valoarea pentru oră"</string> + <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Creșteți valoarea pentru oră"</string> <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Reduceţi valoarea pentru oră"</string> <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Setaţi valoarea PM"</string> <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Setaţi valoarea AM"</string> - <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Creşteţi valoarea pentru lună"</string> + <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Creșteți valoarea pentru lună"</string> <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Reduceţi valoarea pentru lună"</string> - <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Creşteţi valoarea pentru zi"</string> + <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Creșteți valoarea pentru zi"</string> <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_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> @@ -1245,7 +1245,7 @@ <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletă"</string> <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string> <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string> - <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Căşti"</string> + <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Căști"</string> <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Difuz. dispozit. andocare"</string> <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string> <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index f1deb22d3c8d..0621bbe1bd0a 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -915,7 +915,7 @@ <string name="anr_application_process" msgid="8941757607340481057">"Приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" не отвечает. Закрыть его?"</string> <string name="anr_process" msgid="6513209874880517125">"Приложение \"<xliff:g id="PROCESS">%1$s</xliff:g>\" не отвечает.\n\nЗакрыть его?"</string> <string name="force_close" msgid="8346072094521265605">"ОК"</string> - <string name="report" msgid="4060218260984795706">"Отзыв"</string> + <string name="report" msgid="4060218260984795706">"Отправить отчет"</string> <string name="wait" msgid="7147118217226317732">"Подождать"</string> <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница не отвечает.\n\nЗакрыть ее?"</string> <string name="launch_warning_title" msgid="1547997780506713581">"Приложение перенаправлено"</string> diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml index d5bafd259217..582f912b0e80 100644 --- a/core/res/res/values-si-rLK/strings.xml +++ b/core/res/res/values-si-rLK/strings.xml @@ -229,7 +229,7 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"සම්බන්ධතා"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ඔබේ සම්බන්ධතාවලට පිවිසෙන්න"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"ස්ථානය"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"මෙම උපාංගයේ ස්ථානය ප්රවේශ කිරීම"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"මෙම උපාංගයේ ස්ථානයට ප්රවේශ කරන්න"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"දින දර්ශනය"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"ඔබේ දින දර්ශනයට පිවිසෙන්න"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"කෙටි පණිවිඩ"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index cf87e2a67b4c..c5ca3c254b76 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -993,7 +993,7 @@ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ni bilo mogoče zagnati."</string> <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je vklopljen"</string> <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotaknite se za nastavitve"</string> - <string name="accept" msgid="1645267259272829559">"Sprejmi"</string> + <string name="accept" msgid="1645267259272829559">"Sprejmem"</string> <string name="decline" msgid="2112225451706137894">"Zavrni"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Povabilo je poslano"</string> <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Povabilo za povezavo"</string> diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml index 86f9d11fac6c..7df0f86ba96f 100644 --- a/core/res/res/values-sq-rAL/strings.xml +++ b/core/res/res/values-sq-rAL/strings.xml @@ -229,7 +229,7 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktet"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"qasu te kontaktet e tua"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Vendndodhja"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"qasu te vendndodhja e kësaj pajisjeje"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"qasjen te vendndodhja e kësaj pajisjeje"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendari"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"qasu te kalendari yt"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index a3a4b32f0a71..5bb2d781ea72 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -230,21 +230,21 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"приступи контактима"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"приступ локацији овог уређаја"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"приступи локацији овог уређаја"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"приступи календару"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"шаље и прегледа SMS поруке"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Складиште"</string> - <string name="permgroupdesc_storage" msgid="637758554581589203">"приступи сликама, медијима и датотекама на уређају"</string> + <string name="permgroupdesc_storage" msgid="637758554581589203">"приступа сликама, медијима и датотекама на уређају"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string> - <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снимање аудио снимака"</string> + <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио снимке"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"снимање слика и видео снимака"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"снима слике и видео снимке"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string> - <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућивање телефонских позива и управљање њима"</string> + <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућује телефонске позиве и управља њима"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Сензори за тело"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"приступ подацима сензора о виталним функцијама"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"приступа подацима сензора о виталним функцијама"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Преузима садржај прозора"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Проверава садржај прозора са којим остварујете интеракцију."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Укључи Истраживања додиром"</string> @@ -273,7 +273,7 @@ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Омогућава апликацији да чита поруке инфо сервиса које уређај прима. Упозорења инфо сервиса се на неким локацијама примају као упозорења на хитне случајеве. Злонамерне апликације могу да утичу на учинак или ометају функционисање уређаја када се прими порука инфо сервиса о хитном случају."</string> <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"читање пријављених фидова"</string> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Дозвољава апликацији да преузима детаље о тренутно синхронизованим фидовима."</string> - <string name="permlab_sendSms" msgid="7544599214260982981">"шаљи и прегледај SMS поруке"</string> + <string name="permlab_sendSms" msgid="7544599214260982981">"шаље и прегледа SMS поруке"</string> <string name="permdesc_sendSms" msgid="7094729298204937667">"Дозвољава апликацији да шаље SMS поруке. Ово може да доведе до неочекиваних трошкова. Злонамерне апликације могу да шаљу поруке без ваше потврде, што може да изазове трошкове."</string> <string name="permlab_readSms" msgid="8745086572213270480">"читање текстуалних порука (SMS или MMS)"</string> <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Дозвољава апликацији да чита SMS поруке ускладиштене на таблету или SIM картици. Ово омогућава апликацији да чита све SMS поруке, без обзира на садржај или поверљивост."</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 237afe742d2e..29fd6a1be775 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -853,7 +853,7 @@ <string name="Midnight" msgid="5630806906897892201">"Midnatt"</string> <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> - <string name="selectAll" msgid="6876518925844129331">"Välj alla"</string> + <string name="selectAll" msgid="6876518925844129331">"Markera allt"</string> <string name="cut" msgid="3092569408438626261">"Klipp ut"</string> <string name="copy" msgid="2681946229533511987">"Kopiera"</string> <string name="paste" msgid="5629880836805036433">"Klistra in"</string> @@ -1190,7 +1190,7 @@ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Fler alternativ"</string> <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string> <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string> - <string name="storage_internal" msgid="4891916833657929263">"Internminne"</string> + <string name="storage_internal" msgid="4891916833657929263">"lagring"</string> <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string> <string name="storage_sd_card_label" msgid="6347111320774379257">"SD-kort (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string> <string name="storage_usb_drive" msgid="6261899683292244209">"USB-enhet"</string> @@ -1235,7 +1235,7 @@ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara en gång"</string> <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s har inte stöd för arbetsprofil"</string> <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Surfplatta"</string> - <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string> + <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string> <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Mobil"</string> <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hörlurar"</string> <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockningsstationens högtalare"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 6445f6a4a62e..d367887275ac 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -231,7 +231,7 @@ <string name="permgrouplab_contacts" msgid="3657758145679177612">"Anwani"</string> <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ifikie anwani zako"</string> <string name="permgrouplab_location" msgid="7275582855722310164">"Mahali"</string> - <string name="permgroupdesc_location" msgid="1346617465127855033">"fikia mahali kilipo kifaa hiki"</string> + <string name="permgroupdesc_location" msgid="1346617465127855033">"ifikie mahali kilipo kifaa hiki"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalenda"</string> <string name="permgroupdesc_calendar" msgid="3889615280211184106">"fikia kalenda yako"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> diff --git a/core/res/res/values-uz-rUZ-watch/strings.xml b/core/res/res/values-uz-rUZ-watch/strings.xml index 0fe54a194474..44af51d997d5 100644 --- a/core/res/res/values-uz-rUZ-watch/strings.xml +++ b/core/res/res/values-uz-rUZ-watch/strings.xml @@ -22,15 +22,15 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g>dan <xliff:g id="NUMBER_0">%1$d</xliff:g> ilova."</string> <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensorlar"</string> - <string name="permgrouplab_contactswear" msgid="2340286500790908344">"kontaktlarga kirishga ruxsat berish"</string> + <string name="permgrouplab_contactswear" msgid="2340286500790908344">"kontaktlarga kirish"</string> <string name="permgrouplab_locationwear" msgid="6275317222482780209">"mazkur soatning joylashgan joyini ko‘rishga ruxsat berish"</string> <string name="permgrouplab_calendarwear" msgid="441900844045065081">"taqvim ma’lumotlariga kirish"</string> <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS xabarlarni yuborish va ko‘rish"</string> <string name="permgrouplab_storagewear" msgid="1003807594193602313">"Soatingizdagi rasmlar, media va fayllarga kirish"</string> <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ovoz yozib olish"</string> - <string name="permgrouplab_camerawear" msgid="4543951283103407017">"rasmga tushirish va videoga olish"</string> + <string name="permgrouplab_camerawear" msgid="4543951283103407017">"suratga olish va video yozib olish"</string> <string name="permgrouplab_phonewear" msgid="134365036753766126">"telefon qo‘ng‘iroqlarini amalga oshirish va boshqarish"</string> - <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"asosiy belgilaringiz haqidagi sezgich ma’lumotlaridan foydalanishga ruxsat"</string> + <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"organizm holati haqidagi sezgich ma’lumotlariga kirish"</string> <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"holat qatorida ko‘rinishi"</string> <string name="permlab_bodySensorswear" msgid="7857941041202791873">"tana sezgichlari (m-n, yurak urishi sensori) ma’lumotlaridan foydalanishga ruxsat"</string> <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"aniq joylashuv (GPS va tarmoqqa asoslanib) ma’lumotlaridan foydalanishga ruxsat"</string> diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml index 325ad919694f..b7ae9921460c 100644 --- a/core/res/res/values-uz-rUZ/strings.xml +++ b/core/res/res/values-uz-rUZ/strings.xml @@ -231,19 +231,19 @@ <string name="permgrouplab_location" msgid="7275582855722310164">"Joylashuv"</string> <string name="permgroupdesc_location" msgid="1346617465127855033">"qurilmaning joylashuvi haqidagi ma’lumotlarga kirish"</string> <string name="permgrouplab_calendar" msgid="5863508437783683902">"Taqvim"</string> - <string name="permgroupdesc_calendar" msgid="3889615280211184106">"taqvimga kirish"</string> + <string name="permgroupdesc_calendar" msgid="3889615280211184106">"taqvim ma’lumotlariga kirish"</string> <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string> <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS xabarlarni yuborish va ko‘rish"</string> <string name="permgrouplab_storage" msgid="1971118770546336966">"Xotira"</string> - <string name="permgroupdesc_storage" msgid="637758554581589203">"qurilmangizdagi rasm, media va fayllarga kirish"</string> + <string name="permgroupdesc_storage" msgid="637758554581589203">"qurilmangizdagi rasm, multimedia va fayllarga kirish"</string> <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string> <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ovoz yozib olish"</string> <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string> - <string name="permgroupdesc_camera" msgid="3250611594678347720">"rasm va videoga olish"</string> + <string name="permgroupdesc_camera" msgid="3250611594678347720">"suratga olish va video yozib olish"</string> <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string> <string name="permgroupdesc_phone" msgid="6234224354060641055">"telefon qo‘ng‘iroqlarini amalga oshirish va boshqarish"</string> <string name="permgrouplab_sensors" msgid="416037179223226722">"Tana sezgichlari"</string> - <string name="permgroupdesc_sensors" msgid="7147968539346634043">"asosiy belgilaringiz haqidagi sezgich ma’lumotlariga kirish"</string> + <string name="permgroupdesc_sensors" msgid="7147968539346634043">"organizm holati haqidagi sezgich ma’lumotlariga kirish"</string> <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Oynadagi kontentni o‘qiydi"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Joriy oynadagi kontent mazmunini aniqlaydi."</string> <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Teginib o‘rganish xizmatini yoqadi"</string> @@ -342,7 +342,7 @@ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Ilovaga sizning taxminiy joylashuvingizni topishga ruxsat beradi. Ushbu joylashuv Wi-Fi va uyali tarmoq antennalari kabi tarmoq joylashuv manbalaridan foydlanuvchi joylashuv xizmatlari orqali aniqlanadi. Ushbu joylashuv xizmatlari yoqib qo‘yilgan bo‘lishi va qurilmangizdagi ilovaga ulardan foydalanish uchun mavjud bo‘lishi kerak. Ilovalar bundan foydalanib, sizning taxminiy joylashuvingizni aniqlaydi."</string> <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"audio sozlamalaringizni o‘zgartirish"</string> <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Ilovalarga tovush va ovoz chiqarish uchun foydalaniladigan karnay kabi global audio sozlamalarini o‘zgartirish uchun ruxsat beradi."</string> - <string name="permlab_recordAudio" msgid="3876049771427466323">"audioni yozib olish"</string> + <string name="permlab_recordAudio" msgid="3876049771427466323">"ovoz yozib olish"</string> <string name="permdesc_recordAudio" msgid="4906839301087980680">"Ilovaga mikrofon yordamida audio yozish uchun ruxsat beradi. Bu huquq ilovaga ruxsatingizsiz audio fayllarni yozib olishga ruxsat beradi."</string> <string name="permlab_sim_communication" msgid="1180265879464893029">"sim orqali ulanish"</string> <string name="permdesc_sim_communication" msgid="5725159654279639498">"Dasturga SIM kartaga buyruqlar jo‘natishga ruxsat beradi. Bu juda ham xavfli."</string> @@ -797,9 +797,9 @@ <string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string> <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string> <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"delete"</string> - <string name="search_go" msgid="8298016669822141719">"Izlash"</string> + <string name="search_go" msgid="8298016669822141719">"Qidirish"</string> <string name="search_hint" msgid="1733947260773056054">"Qidirish…"</string> - <string name="searchview_description_search" msgid="6749826639098512120">"Izlash"</string> + <string name="searchview_description_search" msgid="6749826639098512120">"Qidirish"</string> <string name="searchview_description_query" msgid="5911778593125355124">"Qidiruv so‘rovi"</string> <string name="searchview_description_clear" msgid="1330281990951833033">"So‘rovni tozalash"</string> <string name="searchview_description_submit" msgid="2688450133297983542">"So‘rov yaratish"</string> @@ -1082,7 +1082,7 @@ <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Masshtabni o‘zgartirish uchun ikki marta bosing"</string> <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidjet qo‘shilmadi."</string> <string name="ime_action_go" msgid="8320845651737369027">"O‘tish"</string> - <string name="ime_action_search" msgid="658110271822807811">"Izlash"</string> + <string name="ime_action_search" msgid="658110271822807811">"Qidirish"</string> <string name="ime_action_send" msgid="2316166556349314424">"Jo‘natish"</string> <string name="ime_action_next" msgid="3138843904009813834">"Keyingi"</string> <string name="ime_action_done" msgid="8971516117910934605">"Tayyor"</string> diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml index 41b05ea8757a..919519e5832a 100644 --- a/core/res/res/values-watch/config.xml +++ b/core/res/res/values-watch/config.xml @@ -54,4 +54,7 @@ <!-- Do not show the message saying USB is connected in charging mode. --> <bool name="config_usbChargingMessage">false</bool> + + <!-- Use a custom transition for RemoteViews. --> + <bool name="config_overrideRemoteViewsActivityTransition">true</bool> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index dc96df4e9d7c..a6eb68b73baa 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -162,6 +162,9 @@ <!-- Text color, typeface, size, and style for small text inside of a popup menu. --> <attr name="textAppearanceSmallPopupMenu" format="reference" /> + <!-- Text color, typeface, size, and style for header text inside of a popup menu. --> + <attr name="textAppearancePopupMenuHeader" format="reference" /> + <!-- The underline color and thickness for easy correct suggestion --> <attr name="textAppearanceEasyCorrectSuggestion" format="reference" /> @@ -729,6 +732,8 @@ i <attr name="listPopupWindowStyle" format="reference" /> <!-- Default PopupMenu style. --> <attr name="popupMenuStyle" format="reference" /> + <!-- Default context menu PopupMenu style. --> + <attr name="contextPopupMenuStyle" format="reference" /> <!-- Default StackView style. --> <attr name="stackViewStyle" format="reference" /> @@ -2150,6 +2155,13 @@ i (which is exiting the screen). The wallpaper remains static behind the animation. --> <attr name="wallpaperIntraCloseExitAnimation" format="reference" /> + + <!-- When opening a new activity from a RemoteViews, this is the + animation that is run on the next activity (which is entering the + screen). Requires config_overrideRemoteViewsActivityTransition to + be true. --> + <attr name="activityOpenRemoteViewsEnterAnimation" format="reference" /> + </declare-styleable> <!-- ============================= --> diff --git a/core/res/res/values/colors_holo.xml b/core/res/res/values/colors_holo.xml index c29fec652652..9d1dda547586 100644 --- a/core/res/res/values/colors_holo.xml +++ b/core/res/res/values/colors_holo.xml @@ -79,8 +79,7 @@ <eat-comment /> <color name="holo_primary_dark">#ff000000</color> - <color name="holo_primary">#ffe6e6e6</color> - <color name="holo_primary_light">#ffffffff</color> + <color name="holo_primary">#ff222222</color> <color name="holo_control_activated">@color/holo_blue_light</color> <color name="holo_control_normal">#39cccccc</color> <color name="holo_button_pressed">#59f0f0f0</color> @@ -88,8 +87,7 @@ <color name="holo_light_primary_dark">#ff000000</color> <color name="holo_light_primary">#ffe6e6e6</color> - <color name="holo_light_primary_light">#ffffffff</color> - <color name="holo_light_control_activated">@color/holo_control_activated</color> + <color name="holo_light_control_activated">@color/holo_blue_light</color> <color name="holo_light_control_normal">#dacccccc</color> <color name="holo_light_button_pressed">#66666666</color> <color name="holo_light_button_normal">#b3cccccc</color> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a19bc202c74d..24d760fddbf8 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -410,6 +410,9 @@ radio is unable to find any MCC information to infer wifi country code from --> <bool translatable="false" name="config_wifi_revert_country_code_on_cellular_loss">false</bool> + <!-- Boolean indicating whether or not wifi firmware debugging is enabled --> + <bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">false</bool> + <!-- Integer specifying the basic autojoin parameters --> <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_threshold">-65</integer> <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_factor">5</integer> @@ -2211,6 +2214,10 @@ <bool name="config_defaultWindowFeatureOptionsPanel">true</bool> <bool name="config_defaultWindowFeatureContextMenu">true</bool> + <!-- If true, the transition for a RemoteViews is read from a resource instead of using the + default scale-up transition. --> + <bool name="config_overrideRemoteViewsActivityTransition">false</bool> + <!-- This config is used to check if the carrier requires converting destination number before sending out a SMS. Formats for this configuration as below: diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 8635a4fac7bc..2621bc9cf219 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -45,6 +45,9 @@ <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. --> <dimen name="status_bar_edge_ignore">5dp</dimen> + <!-- Width of a divider bar used to resize docked stacks. --> + <dimen name="docked_stack_divider_thickness">24dp</dimen> + <!-- Min width for a tablet device --> <dimen name="min_xlarge_screen_width">800dp</dimen> diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml index 55bea9e38291..96a81d138457 100644 --- a/core/res/res/values/dimens_material.xml +++ b/core/res/res/values/dimens_material.xml @@ -72,6 +72,7 @@ <dimen name="text_size_title_material_toolbar">20dp</dimen> <dimen name="text_size_subtitle_material_toolbar">16dp</dimen> <dimen name="text_size_menu_material">16sp</dimen> + <dimen name="text_size_menu_header_material">14sp</dimen> <dimen name="text_size_body_2_material">14sp</dimen> <dimen name="text_size_body_1_material">14sp</dimen> <dimen name="text_size_caption_material">12sp</dimen> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 89d9babbbc1e..f4d0b398561f 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2674,6 +2674,8 @@ <public type="attr" name="buttonGravity" /> <public type="attr" name="collapseIcon" /> <public type="attr" name="level" /> + <public type="attr" name="contextPopupMenuStyle" /> + <public type="attr" name="textAppearancePopupMenuHeader" /> <public type="style" name="Theme.Material.DayNight" /> <public type="style" name="Theme.Material.DayNight.DarkActionBar" /> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 5dc14e301704..38a1693141dc 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -307,6 +307,10 @@ please see styles_device_defaults.xml. <style name="TextAppearance.Material.Widget.PopupMenu"/> <style name="TextAppearance.Material.Widget.PopupMenu.Large" parent="TextAppearance.Material.Menu" /> <style name="TextAppearance.Material.Widget.PopupMenu.Small" parent="TextAppearance.Material.Menu" /> + <style name="TextAppearance.Material.Widget.PopupMenu.Header" parent="TextAppearance.Material.Subhead"> + <item name="fontFamily">@string/font_family_title_material</item> + <item name="textSize">@dimen/text_size_menu_header_material</item> + </style> <style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" /> @@ -471,6 +475,7 @@ please see styles_device_defaults.xml. <style name="Widget.Material.Button.Colored"> <item name="background">@drawable/btn_colored_material</item> <item name="textAppearance">@style/TextAppearance.Material.Widget.Button.Inverse</item> + <item name="textColor">@color/btn_colored_text_material</item> </style> <!-- Small bordered ink button --> @@ -487,7 +492,7 @@ please see styles_device_defaults.xml. <!-- Colored borderless ink button --> <style name="Widget.Material.Button.Borderless.Colored"> - <item name="textColor">@color/btn_colored_text_material</item> + <item name="textColor">@color/btn_colored_borderless_text_material</item> </style> <!-- Alert dialog button bar button --> @@ -862,6 +867,11 @@ please see styles_device_defaults.xml. <item name="dropDownHorizontalOffset">-4dip</item> </style> + <style name="Widget.Material.ContextPopupMenu" parent="Widget.Material.ListPopupWindow"> + <item name="overlapAnchor">true</item> + <item name="popupEnterTransition">@null</item> + </style> + <style name="Widget.Material.ActionButton"> <item name="background">?attr/actionBarItemBackground</item> <item name="paddingStart">12dp</item> diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml index c6052fffd2e2..05835e7b41ab 100644 --- a/core/res/res/values/styles_micro.xml +++ b/core/res/res/values/styles_micro.xml @@ -18,6 +18,7 @@ <style name="Animation.Micro.Activity" parent="Animation.Material.Activity"> <item name="activityOpenEnterAnimation">@anim/slide_in_micro</item> + <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_micro</item> <item name="activityOpenExitAnimation">@null</item> <item name="activityCloseEnterAnimation">@null</item> <item name="activityCloseExitAnimation">@anim/slide_out_micro</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4edc847156c3..06de81d1081e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -307,6 +307,7 @@ <java-symbol type="bool" name="config_wifi_enable_disconnection_debounce" /> <java-symbol type="bool" name="config_wifi_enable_5GHz_preference" /> <java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" /> + <java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" /> <java-symbol type="bool" name="config_supportMicNearUltrasound" /> <java-symbol type="bool" name="config_supportSpeakerNearUltrasound" /> <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" /> @@ -1289,6 +1290,7 @@ <java-symbol type="layout" name="number_picker" /> <java-symbol type="layout" name="permissions_package_list_item" /> <java-symbol type="layout" name="popup_menu_item_layout" /> + <java-symbol type="layout" name="popup_menu_header_item_layout" /> <java-symbol type="layout" name="remote_views_adapter_default_loading_view" /> <java-symbol type="layout" name="search_bar" /> <java-symbol type="layout" name="search_dropdown_item_icons_2line" /> @@ -1477,6 +1479,7 @@ <java-symbol type="bool" name="config_showNavigationBar" /> <java-symbol type="bool" name="config_supportAutoRotation" /> <java-symbol type="bool" name="target_honeycomb_needs_options_menu" /> + <java-symbol type="dimen" name="docked_stack_divider_thickness" /> <java-symbol type="dimen" name="navigation_bar_height" /> <java-symbol type="dimen" name="navigation_bar_height_landscape" /> <java-symbol type="dimen" name="navigation_bar_width" /> @@ -1719,6 +1722,7 @@ <java-symbol type="integer" name="config_undockedHdmiRotation" /> <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" /> <java-symbol type="layout" name="am_compat_mode_dialog" /> + <java-symbol type="layout" name="docked_stack_divider" /> <java-symbol type="layout" name="launch_warning" /> <java-symbol type="layout" name="safe_mode" /> <java-symbol type="layout" name="simple_list_item_2_single_choice" /> @@ -2188,6 +2192,7 @@ <java-symbol type="bool" name="config_sms_force_7bit_encoding" /> <java-symbol type="bool" name="config_defaultWindowFeatureOptionsPanel" /> <java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" /> + <java-symbol type="bool" name="config_overrideRemoteViewsActivityTransition" /> <java-symbol type="layout" name="simple_account_item" /> <java-symbol type="array" name="config_sms_convert_destination_number_support" /> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index 30101909f0b4..59dfc921c392 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -93,6 +93,7 @@ please see themes_device_defaults.xml. <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item> <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item> + <item name="textAppearancePopupMenuHeader">@style/TextAppearance.Material.Widget.PopupMenu.Header</item> <!-- Button styles --> <item name="buttonStyle">@style/Widget.Material.Button</item> @@ -283,6 +284,7 @@ please see themes_device_defaults.xml. <item name="stackViewStyle">@style/Widget.Material.StackView</item> <item name="activityChooserViewStyle">@style/Widget.Material.ActivityChooserView</item> <item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item> + <item name="contextPopupMenuStyle">@style/Widget.Material.ContextPopupMenu</item> <!-- Preference styles --> <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item> @@ -449,6 +451,7 @@ please see themes_device_defaults.xml. <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item> <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item> + <item name="textAppearancePopupMenuHeader">@style/TextAppearance.Material.Widget.PopupMenu.Header</item> <!-- Button styles --> <item name="buttonStyle">@style/Widget.Material.Light.Button</item> @@ -640,6 +643,7 @@ please see themes_device_defaults.xml. <item name="stackViewStyle">@style/Widget.Material.Light.StackView</item> <item name="activityChooserViewStyle">@style/Widget.Material.Light.ActivityChooserView</item> <item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item> + <item name="contextPopupMenuStyle">@style/Widget.Material.ContextPopupMenu</item> <!-- Preference styles --> <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item> diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp index e0b616c16184..3e8301038359 100644 --- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp +++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp @@ -22,7 +22,7 @@ static jint checkFunction(JNIEnv*, jclass) { return 1; } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "checkFunction", "()I", (void*) checkFunction }, }; diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java index b37688f0e212..4db1d9a56c47 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java @@ -17,6 +17,13 @@ package android.widget; import static android.widget.espresso.TextViewActions.clickOnTextAtIndex; +import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText; +import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex; +import static android.widget.espresso.TextViewActions.longPressAndDragOnText; +import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex; +import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex; +import static android.widget.espresso.TextViewAssertions.hasSelection; +import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed; import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.action.ViewActions.pressKey; @@ -56,6 +63,7 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV getActivity(); final String helloWorld = "Hello world!"; + onView(withId(R.id.textview)).perform(click()); onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world"))); @@ -63,4 +71,103 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_FORWARD_DEL)); onView(withId(R.id.textview)).check(matches(withText("Hello orld!"))); } + + @SmallTest + public void testLongPressToSelect() throws Exception { + getActivity(); + + final String helloWorld = "Hello Kirk!"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); + onView(withId(R.id.textview)).perform( + longPressOnTextAtIndex(helloWorld.indexOf("Kirk"))); + + onView(withId(R.id.textview)).check(hasSelection("Kirk")); + } + + @SmallTest + public void testLongPressEmptySpace() throws Exception { + getActivity(); + + final String helloWorld = "Hello big round sun!"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); + // Move cursor somewhere else + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big"))); + // Long-press at end of line. + onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(helloWorld.length())); + + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length())); + } + + @SmallTest + public void testLongPressAndDragToSelect() throws Exception { + getActivity(); + + final String helloWorld = "Hello little handsome boy!"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); + onView(withId(R.id.textview)).perform( + longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!"))); + + onView(withId(R.id.textview)).check(hasSelection("little handsome")); + } + + @SmallTest + public void testDoubleTapToSelect() throws Exception { + getActivity(); + + final String helloWorld = "Hello SuetYi!"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); + onView(withId(R.id.textview)).perform( + doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi"))); + + onView(withId(R.id.textview)).check(hasSelection("SuetYi")); + } + + @SmallTest + public void testDoubleTapAndDragToSelect() throws Exception { + getActivity(); + + final String helloWorld = "Hello young beautiful girl!"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); + onView(withId(R.id.textview)).perform( + doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!"))); + + onView(withId(R.id.textview)).check(hasSelection("young beautiful")); + } + + @SmallTest + public void testSelectBackwordsByTouch() throws Exception { + getActivity(); + + final String helloWorld = "Hello king of the Jungle!"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld)); + onView(withId(R.id.textview)).perform( + doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king"))); + + onView(withId(R.id.textview)).check(hasSelection("king of the")); + } + + @SmallTest + public void testToolbarAppearsAfterSelection() throws Exception { + getActivity(); + + // It'll be nice to check that the toolbar is not visible (or does not exist) here + // I can't currently find a way to do this. I'll get to it later. + + final String text = "Toolbar appears after selection."; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text)); + onView(withId(R.id.textview)).perform( + longPressOnTextAtIndex(text.indexOf("appears"))); + + // It takes the toolbar less than 100ms to start to animate into screen. + // Ideally, we'll wait using the UiController, but I guess this works for now. + Thread.sleep(100); + assertFloatingToolbarIsDisplayed(getActivity()); + } } diff --git a/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java new file mode 100644 index 000000000000..a0cd848a53f5 --- /dev/null +++ b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java @@ -0,0 +1,281 @@ +/* + * 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.widget.espresso; + +import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed; +import static com.android.internal.util.Preconditions.checkNotNull; +import static org.hamcrest.Matchers.allOf; + +import android.annotation.Nullable; +import android.os.SystemClock; +import android.support.test.espresso.UiController; +import android.support.test.espresso.PerformException; +import android.support.test.espresso.ViewAction; +import android.support.test.espresso.action.CoordinatesProvider; +import android.support.test.espresso.action.GeneralClickAction; +import android.support.test.espresso.action.MotionEvents; +import android.support.test.espresso.action.PrecisionDescriber; +import android.support.test.espresso.action.Press; +import android.support.test.espresso.action.Swiper; +import android.support.test.espresso.action.Tap; +import android.support.test.espresso.util.HumanReadables; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.TextView; +import org.hamcrest.Matcher; + + +/** + * Drags on text in a TextView using touch events.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a TextView displayed on screen + * <ul> + */ +public final class DragOnTextViewActions implements ViewAction { + + /** + * Executes different "drag on text" types to given positions. + */ + public enum Drag implements Swiper { + + /** + * Starts a drag with a long-press. + */ + LONG_PRESS { + private DownMotionPerformer downMotion = new DownMotionPerformer() { + @Override + public MotionEvent perform( + UiController uiController, float[] coordinates, float[] precision) { + MotionEvent downEvent = MotionEvents.sendDown( + uiController, coordinates, precision) + .down; + // Duration before a press turns into a long press. + // Factor 1.5 is needed, otherwise a long press is not safely detected. + // See android.test.TouchUtils longClickView + long longPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); + uiController.loopMainThreadForAtLeast(longPressTimeout); + return downEvent; + } + }; + + @Override + public Status sendSwipe( + UiController uiController, + float[] startCoordinates, float[] endCoordinates, float[] precision) { + return sendLinearDrag( + uiController, downMotion, startCoordinates, endCoordinates, precision); + } + + @Override + public String toString() { + return "long press and drag to select"; + } + }, + + /** + * Starts a drag with a double-tap. + */ + DOUBLE_TAP { + private DownMotionPerformer downMotion = new DownMotionPerformer() { + @Override + @Nullable + public MotionEvent perform( + UiController uiController, float[] coordinates, float[] precision) { + MotionEvent downEvent = MotionEvents.sendDown( + uiController, coordinates, precision) + .down; + try { + if (!MotionEvents.sendUp(uiController, downEvent)) { + String logMessage = "Injection of up event as part of the double tap " + + "failed. Sending cancel event."; + Log.d(TAG, logMessage); + MotionEvents.sendCancel(uiController, downEvent); + return null; + } + + long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime(); + uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout); + + return MotionEvents.sendDown(uiController, coordinates, precision).down; + } finally { + downEvent.recycle(); + } + } + }; + + @Override + public Status sendSwipe( + UiController uiController, + float[] startCoordinates, float[] endCoordinates, float[] precision) { + return sendLinearDrag( + uiController, downMotion, startCoordinates, endCoordinates, precision); + } + + @Override + public String toString() { + return "double-tap and drag to select"; + } + }; + + private static final String TAG = Drag.class.getSimpleName(); + + /** The number of move events to send for each drag. */ + private static final int DRAG_STEP_COUNT = 10; + + /** Length of time a drag should last for, in milliseconds. */ + private static final int DRAG_DURATION = 1500; + + private static Status sendLinearDrag( + UiController uiController, DownMotionPerformer downMotion, + float[] startCoordinates, float[] endCoordinates, float[] precision) { + float[][] steps = interpolate(startCoordinates, endCoordinates); + final int delayBetweenMovements = DRAG_DURATION / steps.length; + + MotionEvent downEvent = downMotion.perform(uiController, startCoordinates, precision); + if (downEvent == null) { + return Status.FAILURE; + } + + try { + for (int i = 0; i < steps.length; i++) { + if (!MotionEvents.sendMovement(uiController, downEvent, steps[i])) { + String logMessage = "Injection of move event as part of the drag failed. " + + "Sending cancel event."; + Log.e(TAG, logMessage); + MotionEvents.sendCancel(uiController, downEvent); + return Status.FAILURE; + } + + long desiredTime = downEvent.getDownTime() + delayBetweenMovements * i; + long timeUntilDesired = desiredTime - SystemClock.uptimeMillis(); + if (timeUntilDesired > 10) { + // If the wait time until the next event isn't long enough, skip the wait + // and execute the next event. + uiController.loopMainThreadForAtLeast(timeUntilDesired); + } + } + + if (!MotionEvents.sendUp(uiController, downEvent, endCoordinates)) { + String logMessage = "Injection of up event as part of the drag failed. " + + "Sending cancel event."; + Log.e(TAG, logMessage); + MotionEvents.sendCancel(uiController, downEvent); + return Status.FAILURE; + } + } finally { + downEvent.recycle(); + } + return Status.SUCCESS; + } + + private static float[][] interpolate(float[] start, float[] end) { + float[][] res = new float[DRAG_STEP_COUNT][2]; + + for (int i = 1; i < DRAG_STEP_COUNT + 1; i++) { + res[i - 1][0] = start[0] + (end[0] - start[0]) * i / (DRAG_STEP_COUNT + 2f); + res[i - 1][1] = start[1] + (end[1] - start[1]) * i / (DRAG_STEP_COUNT + 2f); + } + + return res; + } + } + + /** + * Interface to implement different "down motion" types. + */ + private interface DownMotionPerformer { + /** + * Performs and returns a down motion. + * + * @param uiController a UiController to use to send MotionEvents to the screen. + * @param coordinates a float[] with x and y values of center of the tap. + * @param precision a float[] with x and y values of precision of the tap. + * @return the down motion event or null if the down motion event failed. + */ + @Nullable + MotionEvent perform(UiController uiController, float[] coordinates, float[] precision); + } + + private final Swiper mDragger; + private final CoordinatesProvider mStartCoordinatesProvider; + private final CoordinatesProvider mEndCoordinatesProvider; + private final PrecisionDescriber mPrecisionDescriber; + + public DragOnTextViewActions( + Swiper dragger, + CoordinatesProvider startCoordinatesProvider, + CoordinatesProvider endCoordinatesProvider, + PrecisionDescriber precisionDescriber) { + mDragger = checkNotNull(dragger); + mStartCoordinatesProvider = checkNotNull(startCoordinatesProvider); + mEndCoordinatesProvider = checkNotNull(endCoordinatesProvider); + mPrecisionDescriber = checkNotNull(precisionDescriber); + } + + @Override + @SuppressWarnings("unchecked") + public Matcher<View> getConstraints() { + return allOf(isCompletelyDisplayed(), isAssignableFrom(TextView.class)); + } + + @Override + public void perform(UiController uiController, View view) { + checkNotNull(uiController); + checkNotNull(view); + + float[] startCoordinates = mStartCoordinatesProvider.calculateCoordinates(view); + float[] endCoordinates = mEndCoordinatesProvider.calculateCoordinates(view); + float[] precision = mPrecisionDescriber.describePrecision(); + + Swiper.Status status; + + try { + status = mDragger.sendSwipe( + uiController, startCoordinates, endCoordinates, precision); + } catch (RuntimeException re) { + throw new PerformException.Builder() + .withActionDescription(this.getDescription()) + .withViewDescription(HumanReadables.describe(view)) + .withCause(re) + .build(); + } + + int duration = ViewConfiguration.getPressedStateDuration(); + // ensures that all work enqueued to process the swipe has been run. + if (duration > 0) { + uiController.loopMainThreadForAtLeast(duration); + } + + if (status == Swiper.Status.FAILURE) { + throw new PerformException.Builder() + .withActionDescription(getDescription()) + .withViewDescription(HumanReadables.describe(view)) + .withCause(new RuntimeException(getDescription() + " failed")) + .build(); + } + } + + @Override + public String getDescription() { + return mDragger.toString(); + } +} diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java new file mode 100644 index 000000000000..fc01d8416df3 --- /dev/null +++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java @@ -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 + */ + +package android.widget.espresso; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.RootMatchers.withDecorView; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withTagValue; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +import android.app.Activity; +import com.android.internal.widget.FloatingToolbar; + +/** + * Espresso utility methods for the floating toolbar. + */ +public class FloatingToolbarEspressoUtils { + + + private FloatingToolbarEspressoUtils() {} + + /** + * Asserts that the floating toolbar is displayed on screen. + * + * @throws AssertionError if the assertion fails + */ + public static void assertFloatingToolbarIsDisplayed(Activity activity) { + onView(withTagValue(is((Object) FloatingToolbar.FLOATING_TOOLBAR_TAG))) + .inRoot(withDecorView(not(is(activity.getWindow().getDecorView())))) + .check(matches(isDisplayed())); + } + +} diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java index 425dccdf4936..835b1b958860 100644 --- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java +++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java @@ -18,7 +18,6 @@ package android.widget.espresso; import static android.support.test.espresso.action.ViewActions.actionWithAssertions; -import android.content.res.Resources; import android.support.test.espresso.PerformException; import android.support.test.espresso.ViewAction; import android.support.test.espresso.action.CoordinatesProvider; @@ -27,8 +26,6 @@ import android.support.test.espresso.action.Press; import android.support.test.espresso.action.Tap; import android.support.test.espresso.util.HumanReadables; import android.text.Layout; -import android.util.DisplayMetrics; -import android.util.TypedValue; import android.view.View; import android.widget.TextView; @@ -40,12 +37,14 @@ public final class TextViewActions { private TextViewActions() {} /** - * Returns an action that clicks on text at an index on the text view.<br> + * Returns an action that clicks on text at an index on the TextView.<br> * <br> * View constraints: * <ul> - * <li>must be a text view displayed on screen + * <li>must be a TextView displayed on screen * <ul> + * + * @param index The index of the TextView's text to click on. */ public static ViewAction clickOnTextAtIndex(int index) { return actionWithAssertions( @@ -53,6 +52,78 @@ public final class TextViewActions { } /** + * Returns an action that double-clicks on text at an index on the TextView.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a TextView displayed on screen + * <ul> + * + * @param index The index of the TextView's text to double-click on. + */ + public static ViewAction doubleClickOnTextAtIndex(int index) { + return actionWithAssertions( + new GeneralClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER)); + } + + /** + * Returns an action that long presses on text at an index on the TextView.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a TextView displayed on screen + * <ul> + * + * @param index The index of the TextView's text to long press on. + */ + public static ViewAction longPressOnTextAtIndex(int index) { + return actionWithAssertions( + new GeneralClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER)); + } + + /** + * Returns an action that long presses then drags on text from startIndex to endIndex on the + * TextView.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a TextView displayed on screen + * <ul> + * + * @param startIndex The index of the TextView's text to start a drag from + * @param endIndex The index of the TextView's text to end the drag at + */ + public static ViewAction longPressAndDragOnText(int startIndex, int endIndex) { + return actionWithAssertions( + new DragOnTextViewActions( + DragOnTextViewActions.Drag.LONG_PRESS, + new TextCoordinates(startIndex), + new TextCoordinates(endIndex), + Press.FINGER)); + } + + /** + * Returns an action that double taps then drags on text from startIndex to endIndex on the + * TextView.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a TextView displayed on screen + * <ul> + * + * @param startIndex The index of the TextView's text to start a drag from + * @param endIndex The index of the TextView's text to end the drag at + */ + public static ViewAction doubleTapAndDragOnText(int startIndex, int endIndex) { + return actionWithAssertions( + new DragOnTextViewActions( + DragOnTextViewActions.Drag.DOUBLE_TAP, + new TextCoordinates(startIndex), + new TextCoordinates(endIndex), + Press.FINGER)); + } + + /** * A provider of the x, y coordinates of the text at the specified index in a text view. */ private static final class TextCoordinates implements CoordinatesProvider { diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java new file mode 100644 index 000000000000..37c7425ce478 --- /dev/null +++ b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java @@ -0,0 +1,145 @@ +/* + * 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.widget.espresso; + +import static android.support.test.espresso.matcher.ViewMatchers.assertThat; +import static com.android.internal.util.Preconditions.checkNotNull; +import static org.hamcrest.Matchers.is; + +import android.support.test.espresso.NoMatchingViewException; +import android.support.test.espresso.ViewAssertion; +import android.view.View; +import android.widget.TextView; + +import junit.framework.AssertionFailedError; +import org.hamcrest.Matcher; + +/** + * A collection of assertions on a {@link android.widget.TextView}. + */ +public final class TextViewAssertions { + + private TextViewAssertions() {} + + /** + * Returns a {@link ViewAssertion} that asserts that the text view has a specified + * selection.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a text view displayed on screen + * <ul> + * + * @param selection The expected selection. + */ + public static ViewAssertion hasSelection(String selection) { + return hasSelection(is(selection)); + } + + /** + * Returns a {@link ViewAssertion} that asserts that the text view has a specified + * selection.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a text view displayed on screen + * <ul> + * + * @param selection A matcher representing the expected selection. + */ + public static ViewAssertion hasSelection(Matcher<String> selection) { + return new TextSelectionAssertion(selection); + } + + /** + * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at + * a specified index.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a text view displayed on screen + * <ul> + * + * @param index The expected index. + */ + public static ViewAssertion hasInsertionPointerAtIndex(int index) { + return hasInsertionPointerAtIndex(is(index)); + } + + /** + * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at + * a specified index.<br> + * <br> + * View constraints: + * <ul> + * <li>must be a text view displayed on screen + * <ul> + * + * @param index A matcher representing the expected index. + */ + public static ViewAssertion hasInsertionPointerAtIndex(final Matcher<Integer> index) { + return new ViewAssertion() { + @Override + public void check(View view, NoMatchingViewException exception) { + if (view instanceof TextView) { + TextView textView = (TextView) view; + int selectionStart = textView.getSelectionStart(); + int selectionEnd = textView.getSelectionEnd(); + try { + assertThat(selectionStart, index); + assertThat(selectionEnd, index); + } catch (IndexOutOfBoundsException e) { + throw new AssertionFailedError(e.getMessage()); + } + } else { + throw new AssertionFailedError("TextView not found"); + } + } + }; + } + + /** + * A {@link ViewAssertion} to check the selected text in a {@link TextView}. + */ + private static final class TextSelectionAssertion implements ViewAssertion { + + private final Matcher<String> mSelection; + + public TextSelectionAssertion(Matcher<String> selection) { + mSelection = checkNotNull(selection); + } + + @Override + public void check(View view, NoMatchingViewException exception) { + if (view instanceof TextView) { + TextView textView = (TextView) view; + int selectionStart = textView.getSelectionStart(); + int selectionEnd = textView.getSelectionEnd(); + try { + String selectedText = textView.getText() + .subSequence(selectionStart, selectionEnd) + .toString(); + assertThat(selectedText, mSelection); + } catch (IndexOutOfBoundsException e) { + throw new AssertionFailedError(e.getMessage()); + } + } else { + throw new AssertionFailedError("TextView not found"); + } + } + } +} diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp index 4c1615453289..67b12d775828 100644 --- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp +++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp @@ -30,7 +30,7 @@ int result = a + b; static const char *classPathName = "com/framework/shareduid/bit32/Native"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"add", "(II)I", (void*)add }, }; @@ -38,7 +38,7 @@ static JNINativeMethod methods[] = { * Register several native methods for one class. */ static int registerNativeMethods(JNIEnv* env, const char* className, - JNINativeMethod* gMethods, int numMethods) + const JNINativeMethod* gMethods, int numMethods) { jclass clazz; diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp index c2f9f529ee63..342b3bc0ac9a 100644 --- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp +++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp @@ -30,7 +30,7 @@ int result = a + b; static const char *classPathName = "com/framework/shareduid/bit64/Native"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"add", "(II)I", (void*)add }, }; @@ -38,7 +38,7 @@ static JNINativeMethod methods[] = { * Register several native methods for one class. */ static int registerNativeMethods(JNIEnv* env, const char* className, - JNINativeMethod* gMethods, int numMethods) + const JNINativeMethod* gMethods, int numMethods) { jclass clazz; diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp index 5d3ca06968eb..9b38e3e4c437 100644 --- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp +++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp @@ -30,7 +30,7 @@ int result = a + b; static const char *classPathName = "com/framework/shareduid/dual/Native"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"add", "(II)I", (void*)add }, }; @@ -38,7 +38,7 @@ static JNINativeMethod methods[] = { * Register several native methods for one class. */ static int registerNativeMethods(JNIEnv* env, const char* className, - JNINativeMethod* gMethods, int numMethods) + const JNINativeMethod* gMethods, int numMethods) { jclass clazz; diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd index 9dc0ed154208..22ad0c9c4539 100644 --- a/docs/html/tools/support-library/index.jd +++ b/docs/html/tools/support-library/index.jd @@ -665,7 +665,7 @@ page.title=Support Library <li>Added support for a Collapse icon description in the {@link android.support.v7.widget.Toolbar} class.</li> <li>Updated the {@link android.support.v7.widget.SearchView} widget to support displaying - the {@link android.support.v7.mediarouter.R.attr#commitIcon}. </li> + the {@link android.support.v7.appcompat.R.attr#commitIcon}. </li> <li>Removed the <code>buttonGravity</code> attribute from the {@link android.support.v7.widget.Toolbar} class. </li> </ul> diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp index 52597e10609a..63fe8acedd54 100644 --- a/drm/jni/android_drm_DrmManagerClient.cpp +++ b/drm/jni/android_drm_DrmManagerClient.cpp @@ -702,7 +702,7 @@ static jobject android_drm_DrmManagerClient_closeConvertSession( return status; } -static JNINativeMethod nativeMethods[] = { +static const JNINativeMethod nativeMethods[] = { {"_initialize", "()I", (void*)android_drm_DrmManagerClient_initialize}, diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 6582b7e9ef6b..58de87af1a5d 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1526,18 +1526,18 @@ public class Paint { return 0f; } if (!mHasCompatScaling) { - return (float) Math.ceil(native_measureText(text, index, count, mBidiFlags)); + return (float) Math.ceil(native_getTextAdvances(mNativePaint, mNativeTypeface, text, + index, count, index, count, mBidiFlags, null, 0)); } final float oldSize = getTextSize(); - setTextSize(oldSize*mCompatScaling); - float w = native_measureText(text, index, count, mBidiFlags); + setTextSize(oldSize * mCompatScaling); + float w = native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, + count, mBidiFlags, null, 0); setTextSize(oldSize); return (float) Math.ceil(w*mInvCompatScaling); } - private native float native_measureText(char[] text, int index, int count, int bidiFlags); - /** * Return the width of the text. * @@ -1558,18 +1558,17 @@ public class Paint { return 0f; } if (!mHasCompatScaling) { - return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags)); + return (float) Math.ceil(native_getTextAdvances(mNativePaint, mNativeTypeface, text, + start, end, start, end, mBidiFlags, null, 0)); } - final float oldSize = getTextSize(); - setTextSize(oldSize*mCompatScaling); - float w = native_measureText(text, start, end, mBidiFlags); + setTextSize(oldSize * mCompatScaling); + float w = native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, + end, mBidiFlags, null, 0); setTextSize(oldSize); - return (float) Math.ceil(w*mInvCompatScaling); + return (float) Math.ceil(w * mInvCompatScaling); } - private native float native_measureText(String text, int start, int end, int bidiFlags); - /** * Return the width of the text. * @@ -1580,23 +1579,9 @@ public class Paint { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } - - if (text.length() == 0) { - return 0f; - } - - if (!mHasCompatScaling) { - return (float) Math.ceil(native_measureText(text, mBidiFlags)); - } - final float oldSize = getTextSize(); - setTextSize(oldSize*mCompatScaling); - float w = native_measureText(text, mBidiFlags); - setTextSize(oldSize); - return (float) Math.ceil(w*mInvCompatScaling); + return measureText(text, 0, text.length()); } - private native float native_measureText(String text, int bidiFlags); - /** * Return the width of the text. * @@ -1795,17 +1780,20 @@ public class Paint { return 0; } if (!mHasCompatScaling) { - return native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths); + native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, + mBidiFlags, widths, 0); + return count; } final float oldSize = getTextSize(); - setTextSize(oldSize*mCompatScaling); - int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths); + setTextSize(oldSize * mCompatScaling); + native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count, + mBidiFlags, widths, 0); setTextSize(oldSize); - for (int i=0; i<res; i++) { + for (int i = 0; i < count; i++) { widths[i] *= mInvCompatScaling; } - return res; + return count; } /** @@ -1860,7 +1848,7 @@ public class Paint { * @param end The end of the text slice to measure * @param widths array to receive the advance widths of the characters. * Must be at least a large as the text. - * @return the number of unichars in the specified text. + * @return the number of code units in the specified text. */ public int getTextWidths(String text, int start, int end, float[] widths) { if (text == null) { @@ -1877,17 +1865,20 @@ public class Paint { return 0; } if (!mHasCompatScaling) { - return native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths); + native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, + mBidiFlags, widths, 0); + return end - start; } final float oldSize = getTextSize(); - setTextSize(oldSize*mCompatScaling); - int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths); + setTextSize(oldSize * mCompatScaling); + native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end, + mBidiFlags, widths, 0); setTextSize(oldSize); - for (int i=0; i<res; i++) { + for (int i = 0; i < end - start; i++) { widths[i] *= mInvCompatScaling; } - return res; + return end - start; } /** @@ -1896,7 +1887,7 @@ public class Paint { * @param text The text to measure * @param widths array to receive the advance widths of the characters. * Must be at least a large as the text. - * @return the number of unichars in the specified text. + * @return the number of code units in the specified text. */ public int getTextWidths(String text, float[] widths) { return getTextWidths(text, 0, text.length(), widths); @@ -1929,14 +1920,16 @@ public class Paint { return 0f; } if (!mHasCompatScaling) { - return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count, - contextIndex, contextCount, isRtl, advances, advancesIndex); + return native_getTextAdvances(mNativePaint, mNativeTypeface, chars, index, count, + contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, + advancesIndex); } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); - float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count, - contextIndex, contextCount, isRtl, advances, advancesIndex); + float res = native_getTextAdvances(mNativePaint, mNativeTypeface, chars, index, count, + contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, + advancesIndex); setTextSize(oldSize); if (advances != null) { @@ -2039,7 +2032,6 @@ public class Paint { */ public float getTextRunAdvances(String text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float[] advances, int advancesIndex) { - if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -2056,14 +2048,16 @@ public class Paint { } if (!mHasCompatScaling) { - return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end, - contextStart, contextEnd, isRtl, advances, advancesIndex); + return native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, + contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, + advancesIndex); } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); - float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end, - contextStart, contextEnd, isRtl, advances, advancesIndex); + float totalAdvance = native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, + end, contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances, + advancesIndex); setTextSize(oldSize); if (advances != null) { @@ -2511,21 +2505,16 @@ public class Paint { private static native void native_setTextLocale(long native_object, String locale); - private static native int native_getTextWidths(long native_object, long native_typeface, - char[] text, int index, int count, int bidiFlags, float[] widths); - private static native int native_getTextWidths(long native_object, long native_typeface, - String text, int start, int end, int bidiFlags, float[] widths); - private static native int native_getTextGlyphs(long native_object, String text, int start, int end, int contextStart, int contextEnd, int flags, char[] glyphs); - private static native float native_getTextRunAdvances(long native_object, long native_typeface, + private static native float native_getTextAdvances(long native_object, long native_typeface, char[] text, int index, int count, int contextIndex, int contextCount, - boolean isRtl, float[] advances, int advancesIndex); - private static native float native_getTextRunAdvances(long native_object, long native_typeface, + int bidiFlags, float[] advances, int advancesIndex); + private static native float native_getTextAdvances(long native_object, long native_typeface, String text, int start, int end, int contextStart, int contextEnd, - boolean isRtl, float[] advances, int advancesIndex); + int bidiFlags, float[] advances, int advancesIndex); private native int native_getTextRunCursor(long native_object, char[] text, int contextStart, int contextLength, int dir, int offset, int cursorOpt); diff --git a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java new file mode 100644 index 000000000000..b67aa7dca17b --- /dev/null +++ b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java @@ -0,0 +1,165 @@ +/* + * 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.graphics; + +import android.test.AndroidTestCase; + +public class PaintTest extends AndroidTestCase { + public void testGetTextRunAdvances() { + { + // LTR + String text = "abcdef"; + assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), false, true); + assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), false, false); + } + { + // RTL + final String text = + "\u0645\u0627\u0020\u0647\u064A\u0020\u0627\u0644\u0634" + + "\u0641\u0631\u0629\u0020\u0627\u0644\u0645\u0648\u062D" + + "\u062F\u0629\u0020\u064A\u0648\u0646\u064A\u0643\u0648" + + "\u062F\u061F"; + assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), true, true); + assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), true, false); + } + } + + private void assertGetTextRunAdvances(String str, int start, int end, + int contextStart, int contextEnd, boolean isRtl, boolean compareWithOtherMethods) { + Paint p = new Paint(); + + final int count = end - start; + final float[][] advanceArrays = new float[4][count]; + + final float advance = p.getTextRunAdvances(str, start, end, contextStart, contextEnd, + isRtl, advanceArrays[0], 0); + + char chars[] = str.toCharArray(); + final float advance_c = p.getTextRunAdvances(chars, start, count, contextStart, + contextEnd - contextStart, isRtl, advanceArrays[1], 0); + assertEquals(advance, advance_c, 1.0f); + + for (int c = 1; c < count; ++c) { + final float firstPartAdvance = p.getTextRunAdvances(str, start, start + c, + contextStart, contextEnd, isRtl, advanceArrays[2], 0); + final float secondPartAdvance = p.getTextRunAdvances(str, start + c, end, + contextStart, contextEnd, isRtl, advanceArrays[2], c); + assertEquals(advance, firstPartAdvance + secondPartAdvance, 1.0f); + + + final float firstPartAdvance_c = p.getTextRunAdvances(chars, start, c, + contextStart, contextEnd - contextStart, isRtl, advanceArrays[3], 0); + final float secondPartAdvance_c = p.getTextRunAdvances(chars, start + c, + count - c, contextStart, contextEnd - contextStart, isRtl, + advanceArrays[3], c); + assertEquals(advance, firstPartAdvance_c + secondPartAdvance_c, 1.0f); + assertEquals(firstPartAdvance, firstPartAdvance_c, 1.0f); + assertEquals(secondPartAdvance, secondPartAdvance_c, 1.0f); + + for (int i = 1; i < advanceArrays.length; i++) { + for (int j = 0; j < count; j++) { + assertEquals(advanceArrays[0][j], advanceArrays[i][j], 1.0f); + } + } + + // Compare results with measureText, getRunAdvance, and getTextWidths. + if (compareWithOtherMethods && start == contextStart && end == contextEnd) { + assertEquals(advance, p.measureText(str, start, end), 1.0f); + assertEquals(advance, p.getRunAdvance( + str, start, end, contextStart, contextEnd, isRtl, end), 1.0f); + + final float[] widths = new float[count]; + p.getTextWidths(str, start, end, widths); + for (int i = 0; i < count; i++) { + assertEquals(advanceArrays[0][i], widths[i], 1.0f); + } + } + } + } + + public void testGetTextRunAdvances_invalid() { + Paint p = new Paint(); + String text = "test"; + + try { + p.getTextRunAdvances((String)null, 0, 0, 0, 0, false, null, 0); + fail("Should throw an IllegalArgumentException."); + } catch (IllegalArgumentException e) { + } + + try { + p.getTextRunAdvances((CharSequence)null, 0, 0, 0, 0, false, null, 0); + fail("Should throw an IllegalArgumentException."); + } catch (IllegalArgumentException e) { + } + + try { + p.getTextRunAdvances((char[])null, 0, 0, 0, 0, false, null, 0); + fail("Should throw an IllegalArgumentException."); + } catch (IllegalArgumentException e) { + } + + try { + p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false, + new float[text.length() - 1], 0); + fail("Should throw an IndexOutOfBoundsException."); + } catch (IndexOutOfBoundsException e) { + } + + try { + p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false, + new float[text.length()], 1); + fail("Should throw an IndexOutOfBoundsException."); + } catch (IndexOutOfBoundsException e) { + } + + // 0 > contextStart + try { + p.getTextRunAdvances(text, 0, text.length(), -1, text.length(), false, null, 0); + fail("Should throw an IndexOutOfBoundsException."); + } catch (IndexOutOfBoundsException e) { + } + + // contextStart > start + try { + p.getTextRunAdvances(text, 0, text.length(), 1, text.length(), false, null, 0); + fail("Should throw an IndexOutOfBoundsException."); + } catch (IndexOutOfBoundsException e) { + } + + // start > end + try { + p.getTextRunAdvances(text, 1, 0, 0, text.length(), false, null, 0); + fail("Should throw an IndexOutOfBoundsException."); + } catch (IndexOutOfBoundsException e) { + } + + // end > contextEnd + try { + p.getTextRunAdvances(text, 0, text.length(), 0, text.length() - 1, false, null, 0); + fail("Should throw an IndexOutOfBoundsException."); + } catch (IndexOutOfBoundsException e) { + } + + // contextEnd > text.length + try { + p.getTextRunAdvances(text, 0, text.length(), 0, text.length() + 1, false, null, 0); + fail("Should throw an IndexOutOfBoundsException."); + } catch (IndexOutOfBoundsException e) { + } + } +} diff --git a/media/java/android/media/SRTRenderer.java b/media/java/android/media/SRTRenderer.java index ee4edee3f9f0..a3e2abdaeca2 100644 --- a/media/java/android/media/SRTRenderer.java +++ b/media/java/android/media/SRTRenderer.java @@ -165,7 +165,6 @@ class SRTTrack extends WebVttTrack { return; } - final int _ = 0; for (Cue cue : activeCues) { TextTrackCue ttc = (TextTrackCue) cue; @@ -184,7 +183,8 @@ class SRTTrack extends WebVttTrack { parcel.writeInt(buf.length); parcel.writeByteArray(buf); - Message msg = mEventHandler.obtainMessage(MEDIA_TIMED_TEXT, _, _, parcel); + Message msg = mEventHandler.obtainMessage(MEDIA_TIMED_TEXT, 0 /* arg1 */, 0 /* arg2 */, + parcel); mEventHandler.sendMessage(msg); } activeCues.clear(); diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java index 3cd157e2b74f..95cb5206b9b5 100644 --- a/media/java/android/mtp/MtpDevice.java +++ b/media/java/android/mtp/MtpDevice.java @@ -18,6 +18,8 @@ package android.mtp; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; +import android.os.CancellationSignal; +import android.os.OperationCanceledException; import android.os.ParcelFileDescriptor; /** @@ -47,7 +49,7 @@ public final class MtpDevice { /** * Opens the MTP device. Once the device is open it takes ownership of the - * {@link android.hardware.usb.UsbDeviceConnection}. + * {@link android.hardware.usb.UsbDeviceConnection}. * The connection will be closed when you call {@link #close()} * The connection will also be closed if this method fails. * @@ -278,6 +280,38 @@ public final class MtpDevice { return native_send_object_info(info); } + /** + * Reads an event from the device. It blocks the current thread until it gets an event. + * It throws OperationCanceledException if it is cancelled by signal. + * + * @param signal signal for cancellation + * @return obtained event + */ + public MtpEvent readEvent(CancellationSignal signal) { + final int handle = native_submit_event_request(); + + if (handle < 0) { + throw new IllegalStateException("Other thread is reading an event."); + } + + if (signal != null) { + signal.setOnCancelListener(new CancellationSignal.OnCancelListener() { + @Override + public void onCancel() { + native_discard_event_request(handle); + } + }); + } + + try { + return native_reap_event_request(handle); + } finally { + if (signal != null) { + signal.setOnCancelListener(null); + } + } + } + // used by the JNI code private long mNativeContext; @@ -297,4 +331,7 @@ public final class MtpDevice { private native boolean native_import_file(int objectHandle, int fd); private native boolean native_send_object(int objectHandle, int size, int fd); private native MtpObjectInfo native_send_object_info(MtpObjectInfo info); + private native int native_submit_event_request(); + private native MtpEvent native_reap_event_request(int handle); + private native void native_discard_event_request(int handle); } diff --git a/media/java/android/mtp/MtpEvent.java b/media/java/android/mtp/MtpEvent.java new file mode 100644 index 000000000000..0fa7d93e12ca --- /dev/null +++ b/media/java/android/mtp/MtpEvent.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.mtp; + +/** + * This class encapsulates information about a MTP event. + */ +public class MtpEvent { + private int mEventCode; + + /** + * Returns event code of MTP event. + * + * @return event code + */ + public int getEventCode() { return mEventCode; } +} diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp index afb5d5cbba74..b56a3641ac9f 100644 --- a/media/jni/android_media_AmrInputStream.cpp +++ b/media/jni/android_media_AmrInputStream.cpp @@ -119,7 +119,7 @@ static void android_media_AmrInputStream_GsmAmrEncoderDelete // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"GsmAmrEncoderNew", "()J", (void*)android_media_AmrInputStream_GsmAmrEncoderNew}, {"GsmAmrEncoderInitialize", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize}, {"GsmAmrEncoderEncode", "(J[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode}, diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 0034b07762a8..3ffdb17f4ec0 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -1253,7 +1253,7 @@ static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat) // ---------------------------------------------------------------------------- -static JNINativeMethod gImageReaderMethods[] = { +static const JNINativeMethod gImageReaderMethods[] = { {"nativeClassInit", "()V", (void*)ImageReader_classInit }, {"nativeInit", "(Ljava/lang/Object;IIII)V", (void*)ImageReader_init }, {"nativeClose", "()V", (void*)ImageReader_close }, @@ -1263,7 +1263,7 @@ static JNINativeMethod gImageReaderMethods[] = { {"nativeDetachImage", "(Landroid/media/Image;)I", (void*)ImageReader_detachImage }, }; -static JNINativeMethod gImageMethods[] = { +static const JNINativeMethod gImageMethods[] = { {"nativeImageGetBuffer", "(II)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer }, {"nativeCreatePlane", "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;", (void*)Image_createSurfacePlane }, diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 93a44261281b..e8f680f6a36c 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -1798,7 +1798,7 @@ static void android_media_MediaCodec_native_finalize( android_media_MediaCodec_release(env, thiz); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "native_release", "()V", (void *)android_media_MediaCodec_release }, { "native_reset", "()V", (void *)android_media_MediaCodec_reset }, diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp index 82dd48dffeae..de9bf1f528af 100644 --- a/media/jni/android_media_MediaCodecList.cpp +++ b/media/jni/android_media_MediaCodecList.cpp @@ -286,7 +286,7 @@ static jobject android_media_MediaCodecList_getGlobalSettings(JNIEnv *env, jobje static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) { } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount }, { "getCodecName", "(I)Ljava/lang/String;", (void *)android_media_MediaCodecList_getCodecName }, diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp index d7968d225ab2..e414f4838583 100644 --- a/media/jni/android_media_MediaCrypto.cpp +++ b/media/jni/android_media_MediaCrypto.cpp @@ -316,7 +316,7 @@ static void android_media_MediaCrypto_setMediaDrmSession( } } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "release", "()V", (void *)android_media_MediaCrypto_release }, { "native_init", "()V", (void *)android_media_MediaCrypto_native_init }, diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 9ec0312d0f2a..275de1ad5ccb 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -1455,7 +1455,7 @@ static jbyteArray android_media_MediaDrm_signRSANative( } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "release", "()V", (void *)android_media_MediaDrm_release }, { "native_init", "()V", (void *)android_media_MediaDrm_native_init }, diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index 4e9b72685223..96c12dd8665b 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -769,7 +769,7 @@ static void android_media_MediaExtractor_native_finalize( android_media_MediaExtractor_release(env, thiz); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "release", "()V", (void *)android_media_MediaExtractor_release }, { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount }, diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp index 393003d98462..fa0b43fedcef 100644 --- a/media/jni/android_media_MediaHTTPConnection.cpp +++ b/media/jni/android_media_MediaHTTPConnection.cpp @@ -154,7 +154,7 @@ static jint android_media_MediaHTTPConnection_native_readAt( return n; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "native_getIMemory", "()Landroid/os/IBinder;", (void *)android_media_MediaHTTPConnection_native_getIMemory }, diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 59fb6d6f6859..f4e940d6cb21 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -467,7 +467,7 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje } // JNI mapping between Java methods and native methods -static JNINativeMethod nativeMethods[] = { +static const JNINativeMethod nativeMethods[] = { { "_setDataSource", "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp index ecb2ac8a61e8..216624e96ad2 100644 --- a/media/jni/android_media_MediaMuxer.cpp +++ b/media/jni/android_media_MediaMuxer.cpp @@ -219,7 +219,7 @@ static void android_media_MediaMuxer_native_release( } } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeAddTrack", "(J[Ljava/lang/String;[Ljava/lang/Object;)I", (void *)android_media_MediaMuxer_addTrack }, diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index d8041f4bff04..be3672968398 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -1033,7 +1033,7 @@ android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeSetDataSource", "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;" diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp index ca9db91c5eed..580004304170 100644 --- a/media/jni/android_media_MediaProfiles.cpp +++ b/media/jni/android_media_MediaProfiles.cpp @@ -301,7 +301,7 @@ android_media_MediaProfiles_native_get_image_encoding_quality_level(JNIEnv *env, } return static_cast<jint>(levels[index]); } -static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = { +static const JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = { {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, {"native_get_num_file_formats", "()I", (void *)android_media_MediaProfiles_native_get_num_file_formats}, {"native_get_file_format", "(I)I", (void *)android_media_MediaProfiles_native_get_file_format}, @@ -315,7 +315,7 @@ static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = { (void *)android_media_MediaProfiles_native_get_audio_encoder_cap}, }; -static JNINativeMethod gMethodsForCamcorderProfileClass[] = { +static const JNINativeMethod gMethodsForCamcorderProfileClass[] = { {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, {"native_get_camcorder_profile", "(II)Landroid/media/CamcorderProfile;", (void *)android_media_MediaProfiles_native_get_camcorder_profile}, @@ -323,7 +323,7 @@ static JNINativeMethod gMethodsForCamcorderProfileClass[] = { (void *)android_media_MediaProfiles_native_has_camcorder_profile}, }; -static JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = { +static const JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = { {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, {"native_get_num_video_decoders", "()I", (void *)android_media_MediaProfiles_native_get_num_video_decoders}, {"native_get_num_audio_decoders", "()I", (void *)android_media_MediaProfiles_native_get_num_audio_decoders}, @@ -331,7 +331,7 @@ static JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = { {"native_get_audio_decoder_type", "(I)I", (void *)android_media_MediaProfiles_native_get_audio_decoder_type}, }; -static JNINativeMethod gMethodsForCameraProfileClass[] = { +static const JNINativeMethod gMethodsForCameraProfileClass[] = { {"native_init", "()V", (void *)android_media_MediaProfiles_native_init}, {"native_get_num_image_encoding_quality_levels", "(I)I", (void *)android_media_MediaProfiles_native_get_num_image_encoding_quality_levels}, diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index f60af63306ba..e05b3483aadc 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -510,7 +510,7 @@ void android_media_MediaRecorder_setInputSurface( // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"setCamera", "(Landroid/hardware/Camera;)V", (void *)android_media_MediaRecorder_setCamera}, {"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource}, {"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource}, diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp index 1a9384e6b2c8..0f3c61f53a2c 100644 --- a/media/jni/android_media_MediaScanner.cpp +++ b/media/jni/android_media_MediaScanner.cpp @@ -412,7 +412,7 @@ android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz) setNativeScanner_l(env, thiz, 0); } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "processDirectory", "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V", diff --git a/media/jni/android_media_ResampleInputStream.cpp b/media/jni/android_media_ResampleInputStream.cpp index 1549a301772a..d06baa57071d 100644 --- a/media/jni/android_media_ResampleInputStream.cpp +++ b/media/jni/android_media_ResampleInputStream.cpp @@ -107,7 +107,7 @@ static void android_media_ResampleInputStream_fir21(JNIEnv *env, jclass /* clazz // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"fir21", "([BI[BII)V", (void*)android_media_ResampleInputStream_fir21}, }; diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index 713f28ce5684..ec2f98a4c9b4 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -1173,12 +1173,12 @@ android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject /*thiz*/, jlo // ---------------------------------------------------------------------------- -static JNINativeMethod gMtpDatabaseMethods[] = { +static const JNINativeMethod gMtpDatabaseMethods[] = { {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup}, {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize}, }; -static JNINativeMethod gMtpPropertyGroupMethods[] = { +static const JNINativeMethod gMtpPropertyGroupMethods[] = { {"format_date_time", "(J)Ljava/lang/String;", (void *)android_mtp_MtpPropertyGroup_format_date_time}, }; diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp index 2a46ee72e50c..3f4d18386afa 100644 --- a/media/jni/android_mtp_MtpDevice.cpp +++ b/media/jni/android_mtp_MtpDevice.cpp @@ -46,10 +46,14 @@ static jfieldID field_context; jclass clazz_deviceInfo; jclass clazz_storageInfo; jclass clazz_objectInfo; +jclass clazz_event; +jclass clazz_io_exception; +jclass clazz_operation_canceled_exception; jmethodID constructor_deviceInfo; jmethodID constructor_storageInfo; jmethodID constructor_objectInfo; +jmethodID constructor_event; // MtpDeviceInfo fields static jfieldID field_deviceInfo_manufacturer; @@ -86,6 +90,9 @@ static jfieldID field_objectInfo_dateCreated; static jfieldID field_objectInfo_dateModified; static jfieldID field_objectInfo_keywords; +// MtpEvent fields +static jfieldID field_event_eventCode; + MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice) { return (MtpDevice*)env->GetLongField(javaDevice, field_context); @@ -488,9 +495,45 @@ android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info) return result; } +static jint android_mtp_MtpDevice_submit_event_request(JNIEnv *env, jobject thiz) +{ + MtpDevice* const device = get_device_from_object(env, thiz); + if (!device) { + env->ThrowNew(clazz_io_exception, ""); + return -1; + } + return device->submitEventRequest(); +} + +static jobject android_mtp_MtpDevice_reap_event_request(JNIEnv *env, jobject thiz, jint seq) +{ + MtpDevice* const device = get_device_from_object(env, thiz); + if (!device) { + env->ThrowNew(clazz_io_exception, ""); + return NULL; + } + const int eventCode = device->reapEventRequest(seq); + if (eventCode <= 0) { + env->ThrowNew(clazz_operation_canceled_exception, ""); + return NULL; + } + jobject result = env->NewObject(clazz_event, constructor_event); + env->SetIntField(result, field_event_eventCode, eventCode); + return result; +} + +static void android_mtp_MtpDevice_discard_event_request(JNIEnv *env, jobject thiz, jint seq) +{ + MtpDevice* const device = get_device_from_object(env, thiz); + if (!device) { + return; + } + device->discardEventRequest(seq); +} + // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"native_open", "(Ljava/lang/String;I)Z", (void *)android_mtp_MtpDevice_open}, {"native_close", "()V", (void *)android_mtp_MtpDevice_close}, @@ -513,7 +556,11 @@ static JNINativeMethod gMethods[] = { {"native_import_file", "(II)Z",(void *)android_mtp_MtpDevice_import_file_to_fd}, {"native_send_object", "(III)Z",(void *)android_mtp_MtpDevice_send_object}, {"native_send_object_info", "(Landroid/mtp/MtpObjectInfo;)Landroid/mtp/MtpObjectInfo;", - (void *)android_mtp_MtpDevice_send_object_info} + (void *)android_mtp_MtpDevice_send_object_info}, + {"native_submit_event_request", "()I", (void *)android_mtp_MtpDevice_submit_event_request}, + {"native_reap_event_request", "(I)Landroid/mtp/MtpEvent;", + (void *)android_mtp_MtpDevice_reap_event_request}, + {"native_discard_event_request", "(I)V", (void *)android_mtp_MtpDevice_discard_event_request}, }; int register_android_mtp_MtpDevice(JNIEnv *env) @@ -703,6 +750,23 @@ int register_android_mtp_MtpDevice(JNIEnv *env) } clazz_objectInfo = (jclass)env->NewGlobalRef(clazz); + clazz = env->FindClass("android/mtp/MtpEvent"); + if (clazz == NULL) { + ALOGE("Can't find android/mtp/MtpEvent"); + return -1; + } + constructor_event = env->GetMethodID(clazz, "<init>", "()V"); + if (constructor_event == NULL) { + ALOGE("Can't find android/mtp/MtpEvent constructor"); + return -1; + } + field_event_eventCode = env->GetFieldID(clazz, "mEventCode", "I"); + if (field_event_eventCode == NULL) { + ALOGE("Can't find MtpObjectInfo.mEventCode"); + return -1; + } + clazz_event = (jclass)env->NewGlobalRef(clazz); + clazz = env->FindClass("android/mtp/MtpDevice"); if (clazz == NULL) { ALOGE("Can't find android/mtp/MtpDevice"); @@ -713,6 +777,18 @@ int register_android_mtp_MtpDevice(JNIEnv *env) ALOGE("Can't find MtpDevice.mNativeContext"); return -1; } + clazz = env->FindClass("java/io/IOException"); + if (clazz == NULL) { + ALOGE("Can't find java.io.IOException"); + return -1; + } + clazz_io_exception = (jclass)env->NewGlobalRef(clazz); + clazz = env->FindClass("android/os/OperationCanceledException"); + if (clazz == NULL) { + ALOGE("Can't find android.os.OperationCanceledException"); + return -1; + } + clazz_operation_canceled_exception = (jclass)env->NewGlobalRef(clazz); return AndroidRuntime::registerNativeMethods(env, "android/mtp/MtpDevice", gMethods, NELEM(gMethods)); diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp index 2ce2a904e0f0..d13187c39846 100644 --- a/media/jni/android_mtp_MtpServer.cpp +++ b/media/jni/android_mtp_MtpServer.cpp @@ -179,7 +179,7 @@ android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId) // ---------------------------------------------------------------------------- -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"native_setup", "(Landroid/mtp/MtpDatabase;Z)V", (void *)android_mtp_MtpServer_setup}, {"native_run", "()V", (void *)android_mtp_MtpServer_run}, diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index aba4bbeb1e70..fa6913573add 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -879,7 +879,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _ // ---------------------------------------------------------------------------- // Dalvik VM type signatures -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_AudioEffect_native_init}, {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I", (void *)android_media_AudioEffect_native_setup}, diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 05570195752b..3d3adba609c0 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -677,7 +677,7 @@ android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean // ---------------------------------------------------------------------------- // Dalvik VM type signatures -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_visualizer_native_init}, {"native_setup", "(Ljava/lang/Object;I[ILjava/lang/String;)I", (void *)android_media_visualizer_native_setup}, diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk index 1b684bb4e28b..175f73007484 100644 --- a/native/graphics/jni/Android.mk +++ b/native/graphics/jni/Android.mk @@ -31,7 +31,7 @@ LOCAL_MODULE:= libjnigraphics LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -# TODO: This is to work around b/19059885. Remove after root cause is fixed +# TODO: This is to work around b/24465209. Remove after root cause is fixed LOCAL_LDFLAGS_arm := -Wl,--hash-style=both include $(BUILD_SHARED_LIBRARY) diff --git a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml index 969ec599f00c..6a7dbbdfbc65 100644 --- a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml +++ b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml @@ -18,10 +18,10 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="backup_confirm_title" msgid="827563724209303345">"Copiere de rezervă completă"</string> <string name="restore_confirm_title" msgid="5469365809567486602">"Restabilire completă"</string> - <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu aţi solicitat dvs. copierea de rezervă, nu permiteți ca operaţiunea să continue."</string> + <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu aţi solicitat dvs. copierea de rezervă, nu permiteți ca operațiunea să continue."</string> <string name="allow_backup_button_label" msgid="4217228747769644068">"Creaţi copii de rezervă pentru datele dvs."</string> <string name="deny_backup_button_label" msgid="6009119115581097708">"Nu creaţi copii de rezervă"</string> - <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu dvs. aţi solicitat această restabilire, nu permiteți continuarea operaţiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string> + <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu dvs. aţi solicitat această restabilire, nu permiteți continuarea operațiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string> <string name="allow_restore_button_label" msgid="3081286752277127827">"Restabiliţi datele dvs."</string> <string name="deny_restore_button_label" msgid="1724367334453104378">"Nu restabiliţi"</string> <string name="current_password_text" msgid="8268189555578298067">"Introduceţi mai jos parola actuală pentru copia de rezervă:"</string> diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index 0fe5509b95ce..abb464eb3a67 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -76,8 +76,9 @@ public class CaptivePortalLoginActivity extends Activity { String server = Settings.Global.getString(getContentResolver(), "captive_portal_server"); if (server == null) server = DEFAULT_SERVER; mCm = ConnectivityManager.from(this); + String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL); try { - mURL = new URL("http", server, "/generate_204"); + mURL = url != null ? new URL(url) : new URL("http", server, "/generate_204"); } catch (MalformedURLException e) { // System misconfigured, bail out in a way that at least provides network access. Log.e(TAG, "Invalid captive portal URL, server=" + server); diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml index 97bc8fd4d1f4..295cb80ade52 100644 --- a/packages/DocumentsUI/AndroidManifest.xml +++ b/packages/DocumentsUI/AndroidManifest.xml @@ -3,6 +3,7 @@ <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.REMOVE_TASKS" /> + <uses-permission android:name="android.permission.REORDER_TASKS" /> <application android:name=".DocumentsApplication" @@ -35,11 +36,6 @@ <action android:name="android.intent.action.OPEN_DOCUMENT_TREE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> - <intent-filter> - <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" /> - <category android:name="android.intent.category.DEFAULT" /> - <data android:mimeType="vnd.android.document/root" /> - </intent-filter> </activity> <activity @@ -54,8 +50,8 @@ </activity> <activity - android:name=".FilesActivity" - android:theme="@style/FilesTheme" + android:name=".LauncherActivity" + android:theme="@android:style/Theme.NoDisplay" android:icon="@drawable/ic_files_app" android:label="@string/files_label" android:enabled="@bool/productivity_device"> @@ -65,6 +61,22 @@ </intent-filter> </activity> + <activity + android:name=".FilesActivity" + android:theme="@style/FilesTheme" + android:icon="@drawable/ic_files_app" + android:label="@string/files_label" + android:documentLaunchMode="intoExisting"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + </intent-filter> + <intent-filter> + <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:mimeType="vnd.android.document/root" /> + </intent-filter> + </activity> + <provider android:name=".RecentsProvider" android:authorities="com.android.documentsui.recents" diff --git a/packages/DocumentsUI/res/layout/drawer_layout.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml index dec4e923e6ec..0dac0d550eb8 100644 --- a/packages/DocumentsUI/res/layout/drawer_layout.xml +++ b/packages/DocumentsUI/res/layout/drawer_layout.xml @@ -14,62 +14,71 @@ limitations under the License. --> -<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/drawer_layout" +<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and + floating action buttons) to operate correctly. --> +<android.support.design.widget.CoordinatorLayout + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:id="@+id/coordinator_layout"> - <LinearLayout + <android.support.v4.widget.DrawerLayout + android:id="@+id/drawer_layout" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> + android:layout_height="match_parent"> - <com.android.documentsui.DocumentsToolBar - android:id="@+id/toolbar" + <LinearLayout android:layout_width="match_parent" - android:layout_height="?android:attr/actionBarSize" - android:background="?android:attr/colorPrimary" - android:elevation="8dp" - android:theme="?actionBarTheme" - android:popupTheme="?actionBarPopupTheme"> - - <Spinner - android:id="@+id/stack" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="4dp" - android:overlapAnchor="true" /> - - </com.android.documentsui.DocumentsToolBar> - - <include layout="@layout/directory_cluster"/> - - </LinearLayout> - - <LinearLayout - android:id="@+id/drawer_roots" - android:layout_width="256dp" - android:layout_height="match_parent" - android:layout_gravity="start" - android:orientation="vertical" - android:elevation="16dp" - android:background="@*android:color/white"> - - <Toolbar - android:id="@+id/roots_toolbar" - android:layout_width="match_parent" - android:layout_height="?android:attr/actionBarSize" - android:background="?android:attr/colorPrimary" - android:elevation="8dp" - android:theme="?actionBarTheme" - android:popupTheme="?actionBarPopupTheme" /> - - <FrameLayout - android:id="@+id/container_roots" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" /> + android:layout_height="match_parent" + android:orientation="vertical"> + + <com.android.documentsui.DocumentsToolBar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:background="?android:attr/colorPrimary" + android:elevation="8dp" + android:theme="?actionBarTheme" + android:popupTheme="?actionBarPopupTheme"> + + <Spinner + android:id="@+id/stack" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="4dp" + android:overlapAnchor="true" /> + + </com.android.documentsui.DocumentsToolBar> + + <include layout="@layout/directory_cluster"/> + + </LinearLayout> + + <LinearLayout + android:id="@+id/drawer_roots" + android:layout_width="256dp" + android:layout_height="match_parent" + android:layout_gravity="start" + android:orientation="vertical" + android:elevation="16dp" + android:background="@*android:color/white"> + + <Toolbar + android:id="@+id/roots_toolbar" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:background="?android:attr/colorPrimary" + android:elevation="8dp" + android:theme="?actionBarTheme" + android:popupTheme="?actionBarPopupTheme" /> + + <FrameLayout + android:id="@+id/container_roots" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> - </LinearLayout> + </LinearLayout> -</android.support.v4.widget.DrawerLayout> + </android.support.v4.widget.DrawerLayout> +</android.support.design.widget.CoordinatorLayout> diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml index eba9af4297f7..403c6675ac30 100644 --- a/packages/DocumentsUI/res/layout/fixed_layout.xml +++ b/packages/DocumentsUI/res/layout/fixed_layout.xml @@ -14,49 +14,59 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and + floating action buttons) to operate correctly. --> +<android.support.design.widget.CoordinatorLayout + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical"> + android:id="@+id/coordinator_layout"> - <com.android.documentsui.DocumentsToolBar - android:id="@+id/toolbar" + <LinearLayout android:layout_width="match_parent" - android:layout_height="?android:attr/actionBarSize" - android:background="?android:attr/colorPrimary" - android:elevation="8dp" - android:theme="?actionBarTheme" - android:popupTheme="?actionBarPopupTheme"> - - <Spinner - android:id="@+id/stack" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="4dp" - android:overlapAnchor="true" /> - - </com.android.documentsui.DocumentsToolBar> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:orientation="horizontal" - android:baselineAligned="false" - android:divider="?android:attr/dividerVertical" - android:showDividers="middle"> - - <FrameLayout - android:id="@+id/container_roots" - android:layout_width="256dp" - android:layout_height="match_parent" /> - - <include layout="@layout/directory_cluster" - android:layout_width="0dp" - android:layout_weight="1" + android:layout_height="match_parent" + android:orientation="vertical"> + + <com.android.documentsui.DocumentsToolBar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:background="?android:attr/colorPrimary" android:elevation="8dp" - android:background="@color/material_grey_50" /> + android:theme="?actionBarTheme" + android:popupTheme="?actionBarPopupTheme"> + + <Spinner + android:id="@+id/stack" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="4dp" + android:overlapAnchor="true" /> + + </com.android.documentsui.DocumentsToolBar> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:orientation="horizontal" + android:baselineAligned="false" + android:divider="?android:attr/dividerVertical" + android:showDividers="middle"> + + <FrameLayout + android:id="@+id/container_roots" + android:layout_width="256dp" + android:layout_height="match_parent" /> + + <include layout="@layout/directory_cluster" + android:layout_width="0dp" + android:layout_weight="1" + android:elevation="8dp" + android:background="@color/material_grey_50" /> + + </LinearLayout> </LinearLayout> -</LinearLayout> +</android.support.design.widget.CoordinatorLayout> diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml index b02349a693f6..45cb34db54e0 100644 --- a/packages/DocumentsUI/res/layout/fragment_directory.xml +++ b/packages/DocumentsUI/res/layout/fragment_directory.xml @@ -17,61 +17,70 @@ <com.android.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/material_grey_50"> + android:background="@color/material_grey_50" + android:orientation="vertical" + android:animateLayoutChanges="true"> - <TextView - android:id="@android:id/empty" + <ProgressBar + android:id="@+id/progressbar" android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="center" - android:text="@string/empty" - android:visibility="gone" - style="@android:style/TextAppearance.Material.Subhead" /> + android:layout_height="wrap_content" + android:indeterminate="true" + style="@style/TrimmedHorizontalProgressBar" + android:visibility="gone"/> + + <FrameLayout + android:id="@+id/container_message_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:elevation="8dp" + android:background="@color/material_grey_50" + android:visibility="gone"/> + <!-- The empty directory view --> <LinearLayout - android:id="@+id/content" + android:id="@android:id/empty" + android:gravity="center" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:animateLayoutChanges="true"> - - <ProgressBar - android:id="@+id/progressbar" - android:layout_width="match_parent" + android:visibility="gone"> + + <TextView + android:id="@+id/message" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:indeterminate="true" - style="@style/TrimmedHorizontalProgressBar" - android:visibility="gone"/> + android:text="@string/empty" + style="@android:style/TextAppearance.Material.Subhead" /> - <FrameLayout - android:id="@+id/container_message_bar" - android:layout_width="match_parent" + <Button + android:id="@+id/button_retry" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:elevation="8dp" - android:background="@color/material_grey_50" - android:visibility="gone"/> + android:text="@string/button_retry" + style="?android:attr/buttonBarPositiveButtonStyle" /> + + </LinearLayout> + + <!-- This FrameLayout works around b/24189541 --> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> - <!-- This FrameLayout works around b/24189541 --> - <FrameLayout + <android.support.v7.widget.RecyclerView + android:id="@+id/recyclerView" + android:scrollbars="vertical" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:paddingStart="@dimen/grid_padding_horiz" + android:paddingEnd="@dimen/grid_padding_horiz" + android:paddingTop="@dimen/grid_padding_vert" + android:paddingBottom="@dimen/grid_padding_vert" + android:clipToPadding="false" + android:scrollbarStyle="outsideOverlay" + android:drawSelectorOnTop="true" + android:background="@color/directory_background" /> - <android.support.v7.widget.RecyclerView - android:id="@+id/recyclerView" - android:scrollbars="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:paddingStart="@dimen/grid_padding_horiz" - android:paddingEnd="@dimen/grid_padding_horiz" - android:paddingTop="@dimen/grid_padding_vert" - android:paddingBottom="@dimen/grid_padding_vert" - android:clipToPadding="false" - android:scrollbarStyle="outsideOverlay" - android:drawSelectorOnTop="true" - android:background="@color/directory_background" /> - - </FrameLayout> - - </LinearLayout> + </FrameLayout> </com.android.documentsui.DirectoryView> diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml index 20c3232c9686..c5a574568db0 100644 --- a/packages/DocumentsUI/res/layout/single_pane_layout.xml +++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml @@ -14,29 +14,39 @@ limitations under the License. --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and + floating action buttons) to operate correctly. --> +<android.support.design.widget.CoordinatorLayout + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical"> + android:id="@+id/coordinator_layout"> - <com.android.documentsui.DocumentsToolBar - android:id="@+id/toolbar" + <LinearLayout android:layout_width="match_parent" - android:layout_height="?android:attr/actionBarSize" - android:background="?android:attr/colorPrimary" - android:elevation="8dp" - android:theme="?actionBarTheme" - android:popupTheme="?actionBarPopupTheme"> + android:layout_height="match_parent" + android:orientation="vertical"> - <Spinner - android:id="@+id/stack" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="4dp" - android:overlapAnchor="true" /> + <com.android.documentsui.DocumentsToolBar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?android:attr/actionBarSize" + android:background="?android:attr/colorPrimary" + android:elevation="8dp" + android:theme="?actionBarTheme" + android:popupTheme="?actionBarPopupTheme"> - </com.android.documentsui.DocumentsToolBar> + <Spinner + android:id="@+id/stack" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="4dp" + android:overlapAnchor="true" /> - <include layout="@layout/directory_cluster"/> + </com.android.documentsui.DocumentsToolBar> -</LinearLayout> + <include layout="@layout/directory_cluster"/> + + </LinearLayout> + +</android.support.design.widget.CoordinatorLayout> diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml index 7df152fb9775..673a254f63f5 100644 --- a/packages/DocumentsUI/res/menu/activity.xml +++ b/packages/DocumentsUI/res/menu/activity.xml @@ -26,6 +26,7 @@ android:id="@+id/menu_create_dir" android:title="@string/menu_create_dir" android:icon="@drawable/ic_menu_new_folder" + android:alphabeticShortcut="e" android:showAsAction="always" android:visible="false" /> <item @@ -56,11 +57,18 @@ android:icon="@drawable/ic_menu_view_list" android:showAsAction="never" /> <item + android:id="@+id/menu_new_window" + android:title="@string/menu_new_window" + android:alphabeticShortcut="n" + android:showAsAction="never" + android:visible="false" /> + <item android:id="@+id/menu_paste_from_clipboard" android:title="@string/menu_paste_from_clipboard" android:alphabeticShortcut="v" android:showAsAction="never" android:visible="false" /> + <!-- Copy action is defined in mode_directory.xml --> <item android:id="@+id/menu_advanced" android:showAsAction="never" diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml index 0053f2258e33..c2b6dbcaa791 100644 --- a/packages/DocumentsUI/res/values-af/strings.xml +++ b/packages/DocumentsUI/res/values-af/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Kies"</string> <string name="button_copy" msgid="8706475544635021302">"Kopieer"</string> <string name="button_move" msgid="2202666023104202232">"Skuif"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Maak toe"</string> + <string name="button_retry" msgid="4392027584153752797">"Probeer weer"</string> <string name="sort_name" msgid="9183560467917256779">"Volgens naam"</string> <string name="sort_date" msgid="586080032956151448">"Volgens datum gewysig"</string> <string name="sort_size" msgid="3350681319735474741">"Volgens grootte"</string> diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml index eb88830753e6..b82fa937fbac 100644 --- a/packages/DocumentsUI/res/values-am/strings.xml +++ b/packages/DocumentsUI/res/values-am/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"ምረጥ"</string> <string name="button_copy" msgid="8706475544635021302">"ቅዳ"</string> <string name="button_move" msgid="2202666023104202232">"አንቀሳቀስ"</string> + <string name="button_dismiss" msgid="3714065566893946085">"አሰናብት"</string> + <string name="button_retry" msgid="4392027584153752797">"እንደገና ይሞክሩ"</string> <string name="sort_name" msgid="9183560467917256779">"በስም"</string> <string name="sort_date" msgid="586080032956151448">"በተለወጠበት ቀን"</string> <string name="sort_size" msgid="3350681319735474741">"በመጠን"</string> diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml index bf464b606f8f..c7c9ef2405a7 100644 --- a/packages/DocumentsUI/res/values-ar/strings.xml +++ b/packages/DocumentsUI/res/values-ar/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"تحديد"</string> <string name="button_copy" msgid="8706475544635021302">"نسخ"</string> <string name="button_move" msgid="2202666023104202232">"نقل"</string> + <string name="button_dismiss" msgid="3714065566893946085">"إزالة"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string> <string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string> <string name="sort_size" msgid="3350681319735474741">"بحسب الحجم"</string> diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml index 0bd01a5a81ed..8c79cebca33f 100644 --- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml +++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Seçin"</string> <string name="button_copy" msgid="8706475544635021302">"Kopyala"</string> <string name="button_move" msgid="2202666023104202232">"Köçürün"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Rədd edin"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Ad üzrə"</string> <string name="sort_date" msgid="586080032956151448">"Tarix üzrə dəyişmiş"</string> <string name="sort_size" msgid="3350681319735474741">"Ölçü üzrə"</string> diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml index 669145ed2a1f..fdf57d091926 100644 --- a/packages/DocumentsUI/res/values-bg/strings.xml +++ b/packages/DocumentsUI/res/values-bg/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Избиране"</string> <string name="button_copy" msgid="8706475544635021302">"Копиране"</string> <string name="button_move" msgid="2202666023104202232">"Преместване"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Отхвърляне"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"По име"</string> <string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string> <string name="sort_size" msgid="3350681319735474741">"По размер"</string> diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml index 240ba6cfe371..7caf57fbbed7 100644 --- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml +++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"নির্বাচন করুন"</string> <string name="button_copy" msgid="8706475544635021302">"অনুলিপি করুন"</string> <string name="button_move" msgid="2202666023104202232">"সরান"</string> + <string name="button_dismiss" msgid="3714065566893946085">"খারিজ করুন"</string> + <string name="button_retry" msgid="4392027584153752797">"আবার চেষ্টা করুন"</string> <string name="sort_name" msgid="9183560467917256779">"নামের দ্বারা"</string> <string name="sort_date" msgid="586080032956151448">"পরিবর্তনের তারিখ দ্বারা"</string> <string name="sort_size" msgid="3350681319735474741">"আকার অনুযায়ী"</string> diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml index 30accda8fe41..ab365ce82801 100644 --- a/packages/DocumentsUI/res/values-ca/strings.xml +++ b/packages/DocumentsUI/res/values-ca/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Selecciona"</string> <string name="button_copy" msgid="8706475544635021302">"Copia"</string> <string name="button_move" msgid="2202666023104202232">"Desplaça"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Ignora"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Per nom"</string> <string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string> <string name="sort_size" msgid="3350681319735474741">"Per mida"</string> diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml index cb1d9734272b..62b313c94bdc 100644 --- a/packages/DocumentsUI/res/values-cs/strings.xml +++ b/packages/DocumentsUI/res/values-cs/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Vybrat"</string> <string name="button_copy" msgid="8706475544635021302">"Kopírovat"</string> <string name="button_move" msgid="2202666023104202232">"Přesunout"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Zavřít"</string> + <string name="button_retry" msgid="4392027584153752797">"Zkusit znovu"</string> <string name="sort_name" msgid="9183560467917256779">"Podle názvu"</string> <string name="sort_date" msgid="586080032956151448">"Podle data úpravy"</string> <string name="sort_size" msgid="3350681319735474741">"Podle velikosti"</string> diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml index f12737c57bd1..c3d7cdd39d08 100644 --- a/packages/DocumentsUI/res/values-da/strings.xml +++ b/packages/DocumentsUI/res/values-da/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Vælg"</string> <string name="button_copy" msgid="8706475544635021302">"Kopiér"</string> <string name="button_move" msgid="2202666023104202232">"Flyt"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Luk"</string> + <string name="button_retry" msgid="4392027584153752797">"Prøv igen"</string> <string name="sort_name" msgid="9183560467917256779">"Efter navn"</string> <string name="sort_date" msgid="586080032956151448">"Efter ændringsdato"</string> <string name="sort_size" msgid="3350681319735474741">"Efter størrelse"</string> diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml index a7be4db41acc..f88b5c4cb92e 100644 --- a/packages/DocumentsUI/res/values-de/strings.xml +++ b/packages/DocumentsUI/res/values-de/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Auswählen"</string> <string name="button_copy" msgid="8706475544635021302">"Kopieren"</string> <string name="button_move" msgid="2202666023104202232">"Verschieben"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Schließen"</string> + <string name="button_retry" msgid="4392027584153752797">"Erneut versuchen"</string> <string name="sort_name" msgid="9183560467917256779">"Nach Name"</string> <string name="sort_date" msgid="586080032956151448">"Nach Änderungsdatum"</string> <string name="sort_size" msgid="3350681319735474741">"Nach Größe"</string> diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml index 82155a8c11dd..dcca46c776b2 100644 --- a/packages/DocumentsUI/res/values-el/strings.xml +++ b/packages/DocumentsUI/res/values-el/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Επιλογή"</string> <string name="button_copy" msgid="8706475544635021302">"Αντιγραφή"</string> <string name="button_move" msgid="2202666023104202232">"Μετακίνηση"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Παράβλεψη"</string> + <string name="button_retry" msgid="4392027584153752797">"Δοκιμάστε ξανά"</string> <string name="sort_name" msgid="9183560467917256779">"Κατά όνομα"</string> <string name="sort_date" msgid="586080032956151448">"Κατά ημερομηνία τροποποίησης"</string> <string name="sort_size" msgid="3350681319735474741">"Κατά μέγεθος"</string> diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml index c6090475b413..26fd30ff9d38 100644 --- a/packages/DocumentsUI/res/values-en-rAU/strings.xml +++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"select"</string> <string name="button_copy" msgid="8706475544635021302">"Copy"</string> <string name="button_move" msgid="2202666023104202232">"Move"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Dismiss"</string> + <string name="button_retry" msgid="4392027584153752797">"Try again"</string> <string name="sort_name" msgid="9183560467917256779">"By name"</string> <string name="sort_date" msgid="586080032956151448">"By date modified"</string> <string name="sort_size" msgid="3350681319735474741">"By size"</string> diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml index c6090475b413..26fd30ff9d38 100644 --- a/packages/DocumentsUI/res/values-en-rGB/strings.xml +++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"select"</string> <string name="button_copy" msgid="8706475544635021302">"Copy"</string> <string name="button_move" msgid="2202666023104202232">"Move"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Dismiss"</string> + <string name="button_retry" msgid="4392027584153752797">"Try again"</string> <string name="sort_name" msgid="9183560467917256779">"By name"</string> <string name="sort_date" msgid="586080032956151448">"By date modified"</string> <string name="sort_size" msgid="3350681319735474741">"By size"</string> diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml index c6090475b413..26fd30ff9d38 100644 --- a/packages/DocumentsUI/res/values-en-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"select"</string> <string name="button_copy" msgid="8706475544635021302">"Copy"</string> <string name="button_move" msgid="2202666023104202232">"Move"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Dismiss"</string> + <string name="button_retry" msgid="4392027584153752797">"Try again"</string> <string name="sort_name" msgid="9183560467917256779">"By name"</string> <string name="sort_date" msgid="586080032956151448">"By date modified"</string> <string name="sort_size" msgid="3350681319735474741">"By size"</string> diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml index 5936d831acd3..6e805b90d4e4 100644 --- a/packages/DocumentsUI/res/values-es-rUS/strings.xml +++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Seleccionar"</string> <string name="button_copy" msgid="8706475544635021302">"Copiar"</string> <string name="button_move" msgid="2202666023104202232">"Mover"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Descartar"</string> + <string name="button_retry" msgid="4392027584153752797">"Reintentar"</string> <string name="sort_name" msgid="9183560467917256779">"Por nombre"</string> <string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string> <string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string> diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml index 2ed67dd08b19..8fa1d2ed4c63 100644 --- a/packages/DocumentsUI/res/values-es/strings.xml +++ b/packages/DocumentsUI/res/values-es/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Seleccionar"</string> <string name="button_copy" msgid="8706475544635021302">"Copiar"</string> <string name="button_move" msgid="2202666023104202232">"Mover"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string> + <string name="button_retry" msgid="4392027584153752797">"Reintentar"</string> <string name="sort_name" msgid="9183560467917256779">"Por nombre"</string> <string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string> <string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string> diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml index e32936f5de78..7008885bd348 100644 --- a/packages/DocumentsUI/res/values-et-rEE/strings.xml +++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Vali"</string> <string name="button_copy" msgid="8706475544635021302">"Kopeeri"</string> <string name="button_move" msgid="2202666023104202232">"Teisalda"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Loobu"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string> <string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string> <string name="sort_size" msgid="3350681319735474741">"Suuruse järgi"</string> diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml index a1b6fc2fddb6..17d7c660a1bb 100644 --- a/packages/DocumentsUI/res/values-eu-rES/strings.xml +++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Hautatu"</string> <string name="button_copy" msgid="8706475544635021302">"Kopiatu"</string> <string name="button_move" msgid="2202666023104202232">"Mugitu"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Baztertu"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Izenaren arabera"</string> <string name="sort_date" msgid="586080032956151448">"Aldatze-dataren arabera"</string> <string name="sort_size" msgid="3350681319735474741">"Tamainaren arabera"</string> diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml index bbbfe5236aff..c4f6d588ea1c 100644 --- a/packages/DocumentsUI/res/values-fa/strings.xml +++ b/packages/DocumentsUI/res/values-fa/strings.xml @@ -22,7 +22,7 @@ <string name="title_save" msgid="2433679664882857999">"ذخیره در"</string> <string name="menu_create_dir" msgid="5947289605844398389">"ایجاد پوشه"</string> <string name="menu_grid" msgid="6878021334497835259">"نمای جدولی"</string> - <string name="menu_list" msgid="7279285939892417279">"نمای فهرستوار"</string> + <string name="menu_list" msgid="7279285939892417279">"نمای فهرستی"</string> <string name="menu_sort" msgid="7677740407158414452">"مرتبسازی براساس"</string> <string name="menu_search" msgid="3816712084502856974">"جستجو"</string> <string name="menu_settings" msgid="6008033148948428823">"تنظیمات"</string> @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"انتخاب"</string> <string name="button_copy" msgid="8706475544635021302">"کپی"</string> <string name="button_move" msgid="2202666023104202232">"انتقال"</string> + <string name="button_dismiss" msgid="3714065566893946085">"نپذیرفتن"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"براساس نام"</string> <string name="sort_date" msgid="586080032956151448">"براساس تاریخ اصلاح"</string> <string name="sort_size" msgid="3350681319735474741">"براساس اندازه"</string> diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml index fd289a73b4ce..3e873009ce7a 100644 --- a/packages/DocumentsUI/res/values-fi/strings.xml +++ b/packages/DocumentsUI/res/values-fi/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Valitse"</string> <string name="button_copy" msgid="8706475544635021302">"Kopioi"</string> <string name="button_move" msgid="2202666023104202232">"Siirrä"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Hylkää"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string> <string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string> <string name="sort_size" msgid="3350681319735474741">"Koon mukaan"</string> diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml index 342fc9702230..3e82f3403cdc 100644 --- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml +++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Sélectionner"</string> <string name="button_copy" msgid="8706475544635021302">"Copier"</string> <string name="button_move" msgid="2202666023104202232">"Déplacer"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Faire disparaître"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Par nom"</string> <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string> <string name="sort_size" msgid="3350681319735474741">"Par taille"</string> diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml index 7434e2f17ef9..0512ab15ae18 100644 --- a/packages/DocumentsUI/res/values-fr/strings.xml +++ b/packages/DocumentsUI/res/values-fr/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Sélectionner"</string> <string name="button_copy" msgid="8706475544635021302">"Copier"</string> <string name="button_move" msgid="2202666023104202232">"Déplacer"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Fermer"</string> + <string name="button_retry" msgid="4392027584153752797">"Réessayer"</string> <string name="sort_name" msgid="9183560467917256779">"Par nom"</string> <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string> <string name="sort_size" msgid="3350681319735474741">"Par taille"</string> diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml index b74018df88b4..a1cd614f417e 100644 --- a/packages/DocumentsUI/res/values-gl-rES/strings.xml +++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Seleccionar"</string> <string name="button_copy" msgid="8706475544635021302">"Copiar"</string> <string name="button_move" msgid="2202666023104202232">"Mover"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Por nome"</string> <string name="sort_date" msgid="586080032956151448">"Por data de modificación"</string> <string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string> diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml index 58384c92d661..059fb2cb2efb 100644 --- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"પસંદ કરો"</string> <string name="button_copy" msgid="8706475544635021302">"કૉપિ કરો"</string> <string name="button_move" msgid="2202666023104202232">"ખસેડો"</string> + <string name="button_dismiss" msgid="3714065566893946085">"છોડી દો"</string> + <string name="button_retry" msgid="4392027584153752797">"ફરીથી પ્રયત્ન કરો"</string> <string name="sort_name" msgid="9183560467917256779">"નામ દ્વારા"</string> <string name="sort_date" msgid="586080032956151448">"સંશોધન તારીખ દ્વારા"</string> <string name="sort_size" msgid="3350681319735474741">"કદ દ્વારા"</string> diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml index b42c69c7114a..8e33a005f4cc 100644 --- a/packages/DocumentsUI/res/values-hi/strings.xml +++ b/packages/DocumentsUI/res/values-hi/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"चुनें"</string> <string name="button_copy" msgid="8706475544635021302">"कॉपी करें"</string> <string name="button_move" msgid="2202666023104202232">"ले जाएं"</string> + <string name="button_dismiss" msgid="3714065566893946085">"ख़ारिज करें"</string> + <string name="button_retry" msgid="4392027584153752797">"पुनः प्रयास करें"</string> <string name="sort_name" msgid="9183560467917256779">"नाम के अनुसार"</string> <string name="sort_date" msgid="586080032956151448">"बदलाव के दिनांक के अनुसार"</string> <string name="sort_size" msgid="3350681319735474741">"आकार के अनुसार"</string> diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml index 575c7ffe1d9a..4774753aaf60 100644 --- a/packages/DocumentsUI/res/values-hr/strings.xml +++ b/packages/DocumentsUI/res/values-hr/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Odaberi"</string> <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string> <string name="button_move" msgid="2202666023104202232">"Premjesti"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Odbaci"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Po nazivu"</string> <string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string> <string name="sort_size" msgid="3350681319735474741">"Po veličini"</string> diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml index 2d2e3c8b416c..7a521ecc3239 100644 --- a/packages/DocumentsUI/res/values-hu/strings.xml +++ b/packages/DocumentsUI/res/values-hu/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Kiválasztás"</string> <string name="button_copy" msgid="8706475544635021302">"Másolás"</string> <string name="button_move" msgid="2202666023104202232">"Áthelyezés"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Elvetés"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Név szerint"</string> <string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string> <string name="sort_size" msgid="3350681319735474741">"Méret szerint"</string> diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml index 0a4e7a3bedff..95d73f0e5b2e 100644 --- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml +++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Ընտրել"</string> <string name="button_copy" msgid="8706475544635021302">"Պատճենել"</string> <string name="button_move" msgid="2202666023104202232">"Տեղափոխել"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Փակել"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string> <string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string> <string name="sort_size" msgid="3350681319735474741">"Ըստ չափի"</string> diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml index 59aadf12061d..63d415cadf46 100644 --- a/packages/DocumentsUI/res/values-in/strings.xml +++ b/packages/DocumentsUI/res/values-in/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Pilih"</string> <string name="button_copy" msgid="8706475544635021302">"Salin"</string> <string name="button_move" msgid="2202666023104202232">"Pindahkan"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Tutup"</string> + <string name="button_retry" msgid="4392027584153752797">"Coba Lagi"</string> <string name="sort_name" msgid="9183560467917256779">"Menurut nama"</string> <string name="sort_date" msgid="586080032956151448">"Menurut tanggal diubah"</string> <string name="sort_size" msgid="3350681319735474741">"Menurut ukuran"</string> diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml index a0f4987ab904..0c0e47fd4716 100644 --- a/packages/DocumentsUI/res/values-is-rIS/strings.xml +++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Velja"</string> <string name="button_copy" msgid="8706475544635021302">"Afrita"</string> <string name="button_move" msgid="2202666023104202232">"Færa"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Hunsa"</string> + <string name="button_retry" msgid="4392027584153752797">"Reyna aftur"</string> <string name="sort_name" msgid="9183560467917256779">"Eftir heiti"</string> <string name="sort_date" msgid="586080032956151448">"Eftir breytingadags."</string> <string name="sort_size" msgid="3350681319735474741">"Eftir stærð"</string> diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml index ce837daad6cc..de129a7ec0cf 100644 --- a/packages/DocumentsUI/res/values-it/strings.xml +++ b/packages/DocumentsUI/res/values-it/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Seleziona"</string> <string name="button_copy" msgid="8706475544635021302">"Copia"</string> <string name="button_move" msgid="2202666023104202232">"Sposta"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Ignora"</string> + <string name="button_retry" msgid="4392027584153752797">"Riprova"</string> <string name="sort_name" msgid="9183560467917256779">"Per nome"</string> <string name="sort_date" msgid="586080032956151448">"Per data di modifica"</string> <string name="sort_size" msgid="3350681319735474741">"Per dimensioni"</string> diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml index 89e64030124e..dbe463080c82 100644 --- a/packages/DocumentsUI/res/values-iw/strings.xml +++ b/packages/DocumentsUI/res/values-iw/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"בחר"</string> <string name="button_copy" msgid="8706475544635021302">"העתק"</string> <string name="button_move" msgid="2202666023104202232">"העבר"</string> + <string name="button_dismiss" msgid="3714065566893946085">"הסר"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"לפי שם"</string> <string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string> <string name="sort_size" msgid="3350681319735474741">"לפי גודל"</string> diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml index 92e10234f82e..45f0ea1df6f8 100644 --- a/packages/DocumentsUI/res/values-ja/strings.xml +++ b/packages/DocumentsUI/res/values-ja/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"選択"</string> <string name="button_copy" msgid="8706475544635021302">"コピー"</string> <string name="button_move" msgid="2202666023104202232">"移動"</string> + <string name="button_dismiss" msgid="3714065566893946085">"表示しない"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"名前順"</string> <string name="sort_date" msgid="586080032956151448">"更新日順"</string> <string name="sort_size" msgid="3350681319735474741">"サイズ順"</string> diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml index 9a324ba6cef9..114e73c75cb5 100644 --- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml +++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"არჩევა"</string> <string name="button_copy" msgid="8706475544635021302">"კოპირება"</string> <string name="button_move" msgid="2202666023104202232">"გადაადგილება"</string> + <string name="button_dismiss" msgid="3714065566893946085">"დახურვა"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"სახელით"</string> <string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string> <string name="sort_size" msgid="3350681319735474741">"ზომით"</string> diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml index 66f69f529cf1..af123c62b20c 100644 --- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml +++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Таңдау"</string> <string name="button_copy" msgid="8706475544635021302">"Көшіру"</string> <string name="button_move" msgid="2202666023104202232">"Жылжыту"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Өшіру"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Атауы бойынша"</string> <string name="sort_date" msgid="586080032956151448">"Өзгертілген мерзімі бойынша"</string> <string name="sort_size" msgid="3350681319735474741">"Өлшемі бойынша"</string> diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml index 5249d97f6d97..8f3feaedefd1 100644 --- a/packages/DocumentsUI/res/values-km-rKH/strings.xml +++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"ជ្រើស"</string> <string name="button_copy" msgid="8706475544635021302">"ចម្លង"</string> <string name="button_move" msgid="2202666023104202232">"ផ្លាស់ទី"</string> + <string name="button_dismiss" msgid="3714065566893946085">"បដិសេធ"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"តាមឈ្មោះ"</string> <string name="sort_date" msgid="586080032956151448">"តាមកាលបរិច្ឆេទបានកែប្រែ"</string> <string name="sort_size" msgid="3350681319735474741">"តាមទំហំ"</string> diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml index d5eda84388bc..826cf1e3fa73 100644 --- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"ಆಯ್ಕೆಮಾಡು"</string> <string name="button_copy" msgid="8706475544635021302">"ನಕಲಿಸು"</string> <string name="button_move" msgid="2202666023104202232">"ಸರಿಸು"</string> + <string name="button_dismiss" msgid="3714065566893946085">"ವಜಾಗೊಳಿಸಿ"</string> + <string name="button_retry" msgid="4392027584153752797">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string> <string name="sort_name" msgid="9183560467917256779">"ಹೆಸರಿನ ಪ್ರಕಾರ"</string> <string name="sort_date" msgid="586080032956151448">"ಮಾರ್ಪಡಿಸಿರುವ ದಿನಾಂಕದ ಪ್ರಕಾರ"</string> <string name="sort_size" msgid="3350681319735474741">"ಗಾತ್ರದ ಪ್ರಕಾರ"</string> diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml index 77a0df65f4e1..322b43b3bc3a 100644 --- a/packages/DocumentsUI/res/values-ko/strings.xml +++ b/packages/DocumentsUI/res/values-ko/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"선택"</string> <string name="button_copy" msgid="8706475544635021302">"복사"</string> <string name="button_move" msgid="2202666023104202232">"이동"</string> + <string name="button_dismiss" msgid="3714065566893946085">"닫기"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"이름순"</string> <string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string> <string name="sort_size" msgid="3350681319735474741">"크기순"</string> diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml index 14a6331fb526..c8aa69eb3c18 100644 --- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml +++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Тандоо"</string> <string name="button_copy" msgid="8706475544635021302">"Көчүрүү"</string> <string name="button_move" msgid="2202666023104202232">"Жылдыруу"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Этибарга албоо"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Аты боюнча"</string> <string name="sort_date" msgid="586080032956151448">"Өзгөртүлгөн күнү боюнча"</string> <string name="sort_size" msgid="3350681319735474741">"Өлчөмү боюнча"</string> diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml index 2d099f4a2cd6..dedfa0552b36 100644 --- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml +++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"ເລືອກ"</string> <string name="button_copy" msgid="8706475544635021302">"ສຳເນົາ"</string> <string name="button_move" msgid="2202666023104202232">"ຍ້າຍ"</string> + <string name="button_dismiss" msgid="3714065566893946085">"ປິດໄວ້"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string> <string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string> <string name="sort_size" msgid="3350681319735474741">"ຕາມຂະໜາດ"</string> diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml index 7b458add0c47..0c8b44388e00 100644 --- a/packages/DocumentsUI/res/values-lt/strings.xml +++ b/packages/DocumentsUI/res/values-lt/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Pasirinkti"</string> <string name="button_copy" msgid="8706475544635021302">"Kopijuoti"</string> <string name="button_move" msgid="2202666023104202232">"Perkelti"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Atsisakyti"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string> <string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string> <string name="sort_size" msgid="3350681319735474741">"Pagal dydį"</string> diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml index 44909ce48393..5c79554424f7 100644 --- a/packages/DocumentsUI/res/values-lv/strings.xml +++ b/packages/DocumentsUI/res/values-lv/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Atlasīt"</string> <string name="button_copy" msgid="8706475544635021302">"Kopēt"</string> <string name="button_move" msgid="2202666023104202232">"Pārvietot"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Noraidīt"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string> <string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string> <string name="sort_size" msgid="3350681319735474741">"Pēc lieluma"</string> diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml index 7408d0bea25a..b2cb9f1ca2ea 100644 --- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml +++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Избери"</string> <string name="button_copy" msgid="8706475544635021302">"Копирај"</string> <string name="button_move" msgid="2202666023104202232">"Премести"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Отфрли"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"По име"</string> <string name="sort_date" msgid="586080032956151448">"Изменети по датум"</string> <string name="sort_size" msgid="3350681319735474741">"По големина"</string> diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml index af21db914126..07efa66bc871 100644 --- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"തിരഞ്ഞെടുക്കുക"</string> <string name="button_copy" msgid="8706475544635021302">"പകര്ത്തുക"</string> <string name="button_move" msgid="2202666023104202232">"നീക്കുക"</string> + <string name="button_dismiss" msgid="3714065566893946085">"ഡിസ്മിസ് ചെയ്യുക"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"പേര് പ്രകാരം"</string> <string name="sort_date" msgid="586080032956151448">"പരിഷ്ക്കരിച്ച തീയതി പ്രകാരം"</string> <string name="sort_size" msgid="3350681319735474741">"വലുപ്പം പ്രകാരം"</string> diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml index 1475e080bf98..d45778cab5bd 100644 --- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml +++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Сонгох"</string> <string name="button_copy" msgid="8706475544635021302">"Хуулах"</string> <string name="button_move" msgid="2202666023104202232">"Зөөх"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Алгасах"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string> <string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string> <string name="sort_size" msgid="3350681319735474741">"Хэмжээгээр"</string> diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml index b7654881aad3..8d70143ffc0a 100644 --- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"निवडा"</string> <string name="button_copy" msgid="8706475544635021302">"कॉपी करा"</string> <string name="button_move" msgid="2202666023104202232">"हलवा"</string> + <string name="button_dismiss" msgid="3714065566893946085">"डिसमिस करा"</string> + <string name="button_retry" msgid="4392027584153752797">"पुन्हा प्रयत्न करा"</string> <string name="sort_name" msgid="9183560467917256779">"नावानुसार"</string> <string name="sort_date" msgid="586080032956151448">"सुधारित केलेल्या तारखेनुसार"</string> <string name="sort_size" msgid="3350681319735474741">"आकारानुसार"</string> diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml index 46829576e525..22501095b614 100644 --- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml +++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Pilih"</string> <string name="button_copy" msgid="8706475544635021302">"Salin"</string> <string name="button_move" msgid="2202666023104202232">"Alihkan"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Tolak"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string> <string name="sort_date" msgid="586080032956151448">"Mengikut tarikh diubah"</string> <string name="sort_size" msgid="3350681319735474741">"Mengikut saiz"</string> diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml index a422898d8f6d..480c27b1ddfb 100644 --- a/packages/DocumentsUI/res/values-my-rMM/strings.xml +++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"ရွေးရန်"</string> <string name="button_copy" msgid="8706475544635021302">"ကူးယူရန်"</string> <string name="button_move" msgid="2202666023104202232">"ရွေ့မည်"</string> + <string name="button_dismiss" msgid="3714065566893946085">"ပယ်ရန်"</string> + <string name="button_retry" msgid="4392027584153752797">"ထပ် စမ်းကြည့်ပါ"</string> <string name="sort_name" msgid="9183560467917256779">"အမည်ဖြင့်"</string> <string name="sort_date" msgid="586080032956151448">"ပြင်ဆင်မှု ရက်စွဲဖြင့်"</string> <string name="sort_size" msgid="3350681319735474741">"အရွယ်အစားဖြင့်"</string> diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml index 5bcc50f0a62c..48355aab72ba 100644 --- a/packages/DocumentsUI/res/values-nb/strings.xml +++ b/packages/DocumentsUI/res/values-nb/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Velg"</string> <string name="button_copy" msgid="8706475544635021302">"Kopiér"</string> <string name="button_move" msgid="2202666023104202232">"Flytt"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Avvis"</string> + <string name="button_retry" msgid="4392027584153752797">"Prøv på nytt"</string> <string name="sort_name" msgid="9183560467917256779">"Etter navn"</string> <string name="sort_date" msgid="586080032956151448">"Etter endringsdato"</string> <string name="sort_size" msgid="3350681319735474741">"Etter størrelse"</string> diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml index b121035d1490..53942c192ac3 100644 --- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml +++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"चयन गर्नुहोस्"</string> <string name="button_copy" msgid="8706475544635021302">"प्रतिलिपि बनाउनुहोस्"</string> <string name="button_move" msgid="2202666023104202232">"सार्नुहोस्"</string> + <string name="button_dismiss" msgid="3714065566893946085">"खारेज गर्नुहोस्"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"नाम अनुसार"</string> <string name="sort_date" msgid="586080032956151448">"परिमार्जित मिति अनुसार"</string> <string name="sort_size" msgid="3350681319735474741">"आकार अनुसार"</string> diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml index 88ef0bf10ab6..d3e6bbe9cae2 100644 --- a/packages/DocumentsUI/res/values-nl/strings.xml +++ b/packages/DocumentsUI/res/values-nl/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Selecteren"</string> <string name="button_copy" msgid="8706475544635021302">"Kopiëren"</string> <string name="button_move" msgid="2202666023104202232">"Verplaatsen"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Sluiten"</string> + <string name="button_retry" msgid="4392027584153752797">"Opnieuw proberen"</string> <string name="sort_name" msgid="9183560467917256779">"Op naam"</string> <string name="sort_date" msgid="586080032956151448">"Op aanpassingsdatum"</string> <string name="sort_size" msgid="3350681319735474741">"Op grootte"</string> diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml index a55fc276cb65..3b1439653708 100644 --- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"ਚੁਣੋ"</string> <string name="button_copy" msgid="8706475544635021302">"ਕਾਪੀ ਕਰੋ"</string> <string name="button_move" msgid="2202666023104202232">"ਮੂਵ ਕਰੋ"</string> + <string name="button_dismiss" msgid="3714065566893946085">"ਬਰਖਾਸਤ ਕਰੋ"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"ਨਾਮ ਮੁਤਾਬਕ"</string> <string name="sort_date" msgid="586080032956151448">"ਤਾਰੀਖ ਮੁਤਾਬਕ ਸੰਸ਼ੋਧਿਤ"</string> <string name="sort_size" msgid="3350681319735474741">"ਆਕਾਰ ਮੁਤਾਬਕ"</string> diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml index 0099e5a5c061..3e4ef6837726 100644 --- a/packages/DocumentsUI/res/values-pl/strings.xml +++ b/packages/DocumentsUI/res/values-pl/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Wybierz"</string> <string name="button_copy" msgid="8706475544635021302">"Kopiuj"</string> <string name="button_move" msgid="2202666023104202232">"Przenieś"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Zamknij"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string> <string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string> <string name="sort_size" msgid="3350681319735474741">"Według rozmiaru"</string> diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml index 18506dc6f385..ca984cffe69d 100644 --- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml +++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Selecionar"</string> <string name="button_copy" msgid="8706475544635021302">"Copiar"</string> <string name="button_move" msgid="2202666023104202232">"Mover"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Dispensar"</string> + <string name="button_retry" msgid="4392027584153752797">"Tentar novamente"</string> <string name="sort_name" msgid="9183560467917256779">"Por nome"</string> <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string> <string name="sort_size" msgid="3350681319735474741">"Por tamanho"</string> diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml index adf6ec904a32..ab673580ba19 100644 --- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml +++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Selecionar"</string> <string name="button_copy" msgid="8706475544635021302">"Copiar"</string> <string name="button_move" msgid="2202666023104202232">"Mover"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string> + <string name="button_retry" msgid="4392027584153752797">"Tentar novamente"</string> <string name="sort_name" msgid="9183560467917256779">"Por nome"</string> <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string> <string name="sort_size" msgid="3350681319735474741">"Por tamanho"</string> diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml index 18506dc6f385..ca984cffe69d 100644 --- a/packages/DocumentsUI/res/values-pt/strings.xml +++ b/packages/DocumentsUI/res/values-pt/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Selecionar"</string> <string name="button_copy" msgid="8706475544635021302">"Copiar"</string> <string name="button_move" msgid="2202666023104202232">"Mover"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Dispensar"</string> + <string name="button_retry" msgid="4392027584153752797">"Tentar novamente"</string> <string name="sort_name" msgid="9183560467917256779">"Por nome"</string> <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string> <string name="sort_size" msgid="3350681319735474741">"Por tamanho"</string> diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml index 1b046a3c940e..e927b785e2f7 100644 --- a/packages/DocumentsUI/res/values-ro/strings.xml +++ b/packages/DocumentsUI/res/values-ro/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Selectați"</string> <string name="button_copy" msgid="8706475544635021302">"Copiați"</string> <string name="button_move" msgid="2202666023104202232">"Mutați"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Închideți"</string> + <string name="button_retry" msgid="4392027584153752797">"Încercați din nou"</string> <string name="sort_name" msgid="9183560467917256779">"După nume"</string> <string name="sort_date" msgid="586080032956151448">"După data modificării"</string> <string name="sort_size" msgid="3350681319735474741">"După dimensiune"</string> diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml index 84ae160acf38..cdf20cadfc61 100644 --- a/packages/DocumentsUI/res/values-ru/strings.xml +++ b/packages/DocumentsUI/res/values-ru/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Выбрать"</string> <string name="button_copy" msgid="8706475544635021302">"Копировать"</string> <string name="button_move" msgid="2202666023104202232">"Переместить"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Скрыть"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"По названию"</string> <string name="sort_date" msgid="586080032956151448">"По дате изменения"</string> <string name="sort_size" msgid="3350681319735474741">"По размеру"</string> diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml index d9d5818c4943..138f8a6c6b76 100644 --- a/packages/DocumentsUI/res/values-si-rLK/strings.xml +++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"තෝරන්න"</string> <string name="button_copy" msgid="8706475544635021302">"පිටපත් කිරීම"</string> <string name="button_move" msgid="2202666023104202232">"ගෙන යන්න"</string> + <string name="button_dismiss" msgid="3714065566893946085">"ඉවතලන්න"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"නමින්"</string> <string name="sort_date" msgid="586080032956151448">"වෙනස් කරන ලද දිනයෙන්"</string> <string name="sort_size" msgid="3350681319735474741">"ප්රමාණය මගින්"</string> diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml index e0ff5fc0c14e..4310819f08a4 100644 --- a/packages/DocumentsUI/res/values-sk/strings.xml +++ b/packages/DocumentsUI/res/values-sk/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Vybrať"</string> <string name="button_copy" msgid="8706475544635021302">"Kopírovať"</string> <string name="button_move" msgid="2202666023104202232">"Presunúť"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Odmietnuť"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string> <string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string> <string name="sort_size" msgid="3350681319735474741">"Podľa veľkosti"</string> diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml index 83e51244e15c..c9982a7a0233 100644 --- a/packages/DocumentsUI/res/values-sl/strings.xml +++ b/packages/DocumentsUI/res/values-sl/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Izberi"</string> <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string> <string name="button_move" msgid="2202666023104202232">"Premik"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Opusti"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Po imenu"</string> <string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string> <string name="sort_size" msgid="3350681319735474741">"Po velikosti"</string> diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml index 981daf252893..f1ee1bca33eb 100644 --- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml +++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Zgjidh"</string> <string name="button_copy" msgid="8706475544635021302">"Kopjo"</string> <string name="button_move" msgid="2202666023104202232">"Zhvendos"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Largoje"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Sipas emrit"</string> <string name="sort_date" msgid="586080032956151448">"Sipas datës së modifikimit"</string> <string name="sort_size" msgid="3350681319735474741">"Sipas madhësisë"</string> diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml index bd0e9af9723d..c5116c2f78a9 100644 --- a/packages/DocumentsUI/res/values-sr/strings.xml +++ b/packages/DocumentsUI/res/values-sr/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Изабери"</string> <string name="button_copy" msgid="8706475544635021302">"Копирај"</string> <string name="button_move" msgid="2202666023104202232">"Премести"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Одбаци"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Према имену"</string> <string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string> <string name="sort_size" msgid="3350681319735474741">"Према величини"</string> diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml index 2569e00128ed..06e6514d8afb 100644 --- a/packages/DocumentsUI/res/values-sv/strings.xml +++ b/packages/DocumentsUI/res/values-sv/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Välj"</string> <string name="button_copy" msgid="8706475544635021302">"Kopiera"</string> <string name="button_move" msgid="2202666023104202232">"Flytta"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Ta bort permanent"</string> + <string name="button_retry" msgid="4392027584153752797">"Försök igen"</string> <string name="sort_name" msgid="9183560467917256779">"Efter namn"</string> <string name="sort_date" msgid="586080032956151448">"Efter ändringsdatum"</string> <string name="sort_size" msgid="3350681319735474741">"Efter storlek"</string> diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml index ce186d7b3be7..79bae1f94cc8 100644 --- a/packages/DocumentsUI/res/values-sw/strings.xml +++ b/packages/DocumentsUI/res/values-sw/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Teua"</string> <string name="button_copy" msgid="8706475544635021302">"Nakili"</string> <string name="button_move" msgid="2202666023104202232">"Hamisha"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Ondoa"</string> + <string name="button_retry" msgid="4392027584153752797">"Jaribu Tena"</string> <string name="sort_name" msgid="9183560467917256779">"Kwa jina"</string> <string name="sort_date" msgid="586080032956151448">"Kwa tarehe viliporekebishwa"</string> <string name="sort_size" msgid="3350681319735474741">"Kwa ukubwa"</string> diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml index b7b9c093cad5..117aabce296e 100644 --- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"தேர்ந்தெடு"</string> <string name="button_copy" msgid="8706475544635021302">"நகலெடு"</string> <string name="button_move" msgid="2202666023104202232">"நகர்த்து"</string> + <string name="button_dismiss" msgid="3714065566893946085">"நிராகரி"</string> + <string name="button_retry" msgid="4392027584153752797">"மீண்டும் முயற்சிக்கவும்"</string> <string name="sort_name" msgid="9183560467917256779">"பெயரின்படி"</string> <string name="sort_date" msgid="586080032956151448">"திருத்தப்பட்ட தேதியின்படி"</string> <string name="sort_size" msgid="3350681319735474741">"அளவின்படி"</string> diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml index 7a814862c656..21b7f586c3d6 100644 --- a/packages/DocumentsUI/res/values-te-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"ఎంచుకోండి"</string> <string name="button_copy" msgid="8706475544635021302">"కాపీ చేయి"</string> <string name="button_move" msgid="2202666023104202232">"తరలించు"</string> + <string name="button_dismiss" msgid="3714065566893946085">"తీసివేయి"</string> + <string name="button_retry" msgid="4392027584153752797">"మళ్లీ ప్రయత్నించు"</string> <string name="sort_name" msgid="9183560467917256779">"పేరు ద్వారా"</string> <string name="sort_date" msgid="586080032956151448">"సవరించిన తేదీ ద్వారా"</string> <string name="sort_size" msgid="3350681319735474741">"పరిమాణం ద్వారా"</string> diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml index 87c0a739cf17..8a49708ad591 100644 --- a/packages/DocumentsUI/res/values-th/strings.xml +++ b/packages/DocumentsUI/res/values-th/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"เลือก"</string> <string name="button_copy" msgid="8706475544635021302">"คัดลอก"</string> <string name="button_move" msgid="2202666023104202232">"ย้าย"</string> + <string name="button_dismiss" msgid="3714065566893946085">"ปิด"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string> <string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string> <string name="sort_size" msgid="3350681319735474741">"ตามขนาด"</string> diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml index eaef936365e2..5c0dc12e0353 100644 --- a/packages/DocumentsUI/res/values-tl/strings.xml +++ b/packages/DocumentsUI/res/values-tl/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Pumili"</string> <string name="button_copy" msgid="8706475544635021302">"Kopyahin"</string> <string name="button_move" msgid="2202666023104202232">"Ilipat"</string> + <string name="button_dismiss" msgid="3714065566893946085">"I-dismiss"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string> <string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string> <string name="sort_size" msgid="3350681319735474741">"Ayon sa laki"</string> diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml index 8c0596f418cc..092b38ee7eef 100644 --- a/packages/DocumentsUI/res/values-tr/strings.xml +++ b/packages/DocumentsUI/res/values-tr/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Seç"</string> <string name="button_copy" msgid="8706475544635021302">"Kopyala"</string> <string name="button_move" msgid="2202666023104202232">"Taşı"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Kapat"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Ada göre"</string> <string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string> <string name="sort_size" msgid="3350681319735474741">"Boyuta göre"</string> diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml index 9bbc59abb0d2..dff37c3eb316 100644 --- a/packages/DocumentsUI/res/values-uk/strings.xml +++ b/packages/DocumentsUI/res/values-uk/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Вибрати"</string> <string name="button_copy" msgid="8706475544635021302">"Копіювати"</string> <string name="button_move" msgid="2202666023104202232">"Перемістити"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Закрити"</string> + <string name="button_retry" msgid="4392027584153752797">"Повторити спробу"</string> <string name="sort_name" msgid="9183560467917256779">"За назвою"</string> <string name="sort_date" msgid="586080032956151448">"За датою змінення"</string> <string name="sort_size" msgid="3350681319735474741">"За розміром"</string> diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml index 0c12aa1bcd7a..82822ecdfe8d 100644 --- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml +++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"منتخب کریں"</string> <string name="button_copy" msgid="8706475544635021302">"کاپی کریں"</string> <string name="button_move" msgid="2202666023104202232">"منتقل کریں"</string> + <string name="button_dismiss" msgid="3714065566893946085">"برخاست کریں"</string> + <string name="button_retry" msgid="4392027584153752797">"دوبارہ کوشش کریں"</string> <string name="sort_name" msgid="9183560467917256779">"نام کے لحاظ سے"</string> <string name="sort_date" msgid="586080032956151448">"ترمیم کی تاریخ کے لحاظ سے"</string> <string name="sort_size" msgid="3350681319735474741">"سائز کے لحاظ سے"</string> diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml index ec918857d09d..d0cfacc8bc8c 100644 --- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml +++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml @@ -24,7 +24,7 @@ <string name="menu_grid" msgid="6878021334497835259">"Katak ko‘rinishida"</string> <string name="menu_list" msgid="7279285939892417279">"Ro‘yxat ko‘rinishida"</string> <string name="menu_sort" msgid="7677740407158414452">"Saralash"</string> - <string name="menu_search" msgid="3816712084502856974">"Izlash"</string> + <string name="menu_search" msgid="3816712084502856974">"Qidirish"</string> <string name="menu_settings" msgid="6008033148948428823">"Sozlamalar"</string> <string name="menu_open" msgid="432922957274920903">"Ochish"</string> <string name="menu_save" msgid="2394743337684426338">"Saqlash"</string> @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Tanlash"</string> <string name="button_copy" msgid="8706475544635021302">"Nusxalash"</string> <string name="button_move" msgid="2202666023104202232">"Ko‘chirib o‘tkazish"</string> + <string name="button_dismiss" msgid="3714065566893946085">"O‘chirish"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Nomi bo‘yicha"</string> <string name="sort_date" msgid="586080032956151448">"Tahrir sanasi bo‘yicha"</string> <string name="sort_size" msgid="3350681319735474741">"Hajmi bo‘yicha"</string> diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml index a652ecc950bf..4583362fc6ab 100644 --- a/packages/DocumentsUI/res/values-vi/strings.xml +++ b/packages/DocumentsUI/res/values-vi/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"Chọn"</string> <string name="button_copy" msgid="8706475544635021302">"Sao chép"</string> <string name="button_move" msgid="2202666023104202232">"Di chuyển"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Loại bỏ"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"Theo tên"</string> <string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string> <string name="sort_size" msgid="3350681319735474741">"Theo kích thước"</string> diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml index b0f548083cff..d577e14c8f40 100644 --- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml +++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"选择"</string> <string name="button_copy" msgid="8706475544635021302">"复制"</string> <string name="button_move" msgid="2202666023104202232">"移动"</string> + <string name="button_dismiss" msgid="3714065566893946085">"关闭"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"按名称"</string> <string name="sort_date" msgid="586080032956151448">"按修改日期"</string> <string name="sort_size" msgid="3350681319735474741">"按大小"</string> diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml index 220b71695685..3d44047126b9 100644 --- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml +++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"選取"</string> <string name="button_copy" msgid="8706475544635021302">"複製"</string> <string name="button_move" msgid="2202666023104202232">"移動"</string> + <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"按名稱"</string> <string name="sort_date" msgid="586080032956151448">"按修改日期"</string> <string name="sort_size" msgid="3350681319735474741">"按大小"</string> diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml index 9c21aa59fbaa..aaad98c89851 100644 --- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml +++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml @@ -44,6 +44,9 @@ <string name="button_select" msgid="527196987259139214">"選取"</string> <string name="button_copy" msgid="8706475544635021302">"複製"</string> <string name="button_move" msgid="2202666023104202232">"移動"</string> + <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string> + <!-- no translation found for button_retry (4392027584153752797) --> + <skip /> <string name="sort_name" msgid="9183560467917256779">"依名稱"</string> <string name="sort_date" msgid="586080032956151448">"依修改日期"</string> <string name="sort_size" msgid="3350681319735474741">"依大小"</string> diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml index 5ce9f12a3867..8f20cc4db941 100644 --- a/packages/DocumentsUI/res/values-zu/strings.xml +++ b/packages/DocumentsUI/res/values-zu/strings.xml @@ -44,6 +44,8 @@ <string name="button_select" msgid="527196987259139214">"Khetha"</string> <string name="button_copy" msgid="8706475544635021302">"Kopisha"</string> <string name="button_move" msgid="2202666023104202232">"Hambisa"</string> + <string name="button_dismiss" msgid="3714065566893946085">"Cashisa"</string> + <string name="button_retry" msgid="4392027584153752797">"Zama futhi"</string> <string name="sort_name" msgid="9183560467917256779">"Ngegama"</string> <string name="sort_date" msgid="586080032956151448">"Ngedethi yokuguqula"</string> <string name="sort_size" msgid="3350681319735474741">"Ngosayizi"</string> diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml index ed7820b01b48..ce5b17432e8e 100644 --- a/packages/DocumentsUI/res/values/config.xml +++ b/packages/DocumentsUI/res/values/config.xml @@ -15,5 +15,5 @@ --> <resources> - <bool name="productivity_device">true</bool> + <bool name="productivity_device">false</bool> </resources> diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml index 28018f8eceec..a4acb604c1ef 100644 --- a/packages/DocumentsUI/res/values/strings.xml +++ b/packages/DocumentsUI/res/values/strings.xml @@ -54,6 +54,8 @@ <!-- Menu item title that moves the selected documents [CHAR LIMIT=24] --> <string name="menu_move">Move to\u2026</string> + <!-- Menu item title that creates a new window in the activity [CHAR LIMIT=24] --> + <string name="menu_new_window">New window</string> <!-- Menu item title that copies the selected documents to clipboard [CHAR LIMIT=24] --> <string name="menu_copy_to_clipboard">Copy</string> <!-- Menu item title that pastes files from the clipboard [CHAR LIMIT=24] --> @@ -81,7 +83,8 @@ <string name="button_move">Move</string> <!-- Button label that hides the error bar [CHAR LIMIT=24] --> <string name="button_dismiss">Dismiss</string> - + <string name="button_retry">Try Again</string> + <!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] --> <string name="sort_name">By name</string> <!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] --> diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index 4d0a7eb67483..a6a45e59f469 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -16,13 +16,6 @@ package com.android.documentsui; -import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE; -import static com.android.documentsui.BaseActivity.State.ACTION_CREATE; -import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT; -import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE; import static com.android.documentsui.DirectoryFragment.ANIM_DOWN; import static com.android.documentsui.DirectoryFragment.ANIM_NONE; import static com.android.documentsui.DirectoryFragment.ANIM_SIDE; @@ -40,14 +33,11 @@ import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Root; import android.support.annotation.LayoutRes; import android.support.annotation.Nullable; import android.util.Log; -import android.util.SparseArray; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -74,7 +64,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.concurrent.Executor; @@ -86,10 +75,11 @@ abstract class BaseActivity extends Activity { RootsCache mRoots; SearchManager mSearchManager; DrawerController mDrawer; + boolean mProductivityDevice; + private final String mTag; @LayoutRes private int mLayoutId; - private final String mTag; private DirectoryContainerView mDirectoryContainer; public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings); @@ -110,6 +100,7 @@ abstract class BaseActivity extends Activity { public void onCreate(Bundle icicle) { super.onCreate(icicle); + mProductivityDevice = getResources().getBoolean(R.bool.productivity_device); mState = (icicle != null) ? icicle.<State>getParcelable(EXTRA_STATE) : buildState(); @@ -125,22 +116,6 @@ abstract class BaseActivity extends Activity { } @Override - public void onResume() { - super.onResume(); - - final State state = getDisplayState(); - final RootInfo root = getCurrentRoot(); - - // If we're browsing a specific root, and that root went away, then we - // have no reason to hang around - if (state.action == State.ACTION_BROWSE && root != null) { - if (mRoots.getRootBlocking(root.authority, root.rootId) == null) { - finish(); - } - } - } - - @Override public boolean onCreateOptionsMenu(Menu menu) { boolean showMenu = super.onCreateOptionsMenu(menu); @@ -178,8 +153,10 @@ abstract class BaseActivity extends Activity { State state = getDisplayState(); sortSize.setVisible(state.showSize); // Only sort by size when visible + fileSize.setVisible(!state.showSize); grid.setVisible(state.derivedMode != State.MODE_GRID); list.setVisible(state.derivedMode != State.MODE_LIST); + advanced.setVisible(!mState.showAdvanced); settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0); return shown; @@ -189,13 +166,17 @@ abstract class BaseActivity extends Activity { State state = new State(); final Intent intent = getIntent(); - final String action = intent.getAction(); state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false); + + state.forceSize = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, false); + state.showSize = state.forceSize || LocalPreferences.getDisplayFileSize(this); + state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false); - state.showAdvanced = state.forceAdvanced || - LocalPreferences.getDisplayAdvancedDevices(this); + state.showAdvanced = state.forceAdvanced + || LocalPreferences.getDisplayAdvancedDevices(this); + state.initAcceptMimes(intent); state.excludedAuthorities = getExcludedAuthorities(); return state; @@ -219,7 +200,7 @@ abstract class BaseActivity extends Activity { if (mRoots.isRecentsRoot(root)) { onCurrentDirectoryChanged(ANIM_SIDE); } else { - new PickRootTask(root).executeOnExecutor(getCurrentExecutor()); + new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory()); } } @@ -229,6 +210,7 @@ abstract class BaseActivity extends Activity { switch (item.getItemId()) { case R.id.menu_advanced: case R.id.menu_file_size: + case R.id.menu_new_window: break; default: item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); @@ -384,118 +366,6 @@ abstract class BaseActivity extends Activity { public static String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY"; } - public static class State implements android.os.Parcelable { - public int action; - public String[] acceptMimes; - - /** Explicit user choice */ - public int userMode = MODE_UNKNOWN; - /** Derived after loader */ - public int derivedMode = MODE_LIST; - - /** Explicit user choice */ - public int userSortOrder = SORT_ORDER_UNKNOWN; - /** Derived after loader */ - public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME; - - public boolean allowMultiple; - public boolean showSize; - public boolean localOnly ; - public boolean forceAdvanced ; - public boolean showAdvanced ; - public boolean stackTouched ; - public boolean restored ; - public boolean directoryCopy ; - /** Transfer mode for file copy/move operations. */ - public int transferMode; - - /** Current user navigation stack; empty implies recents. */ - public DocumentStack stack = new DocumentStack(); - /** Currently active search, overriding any stack. */ - public String currentSearch; - - /** Instance state for every shown directory */ - public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>(); - - /** Currently copying file */ - public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>(); - - /** Name of the package that started DocsUI */ - public List<String> excludedAuthorities = new ArrayList<>(); - - public static final int ACTION_OPEN = 1; - public static final int ACTION_CREATE = 2; - public static final int ACTION_GET_CONTENT = 3; - public static final int ACTION_OPEN_TREE = 4; - public static final int ACTION_MANAGE = 5; - public static final int ACTION_BROWSE = 6; - public static final int ACTION_BROWSE_ALL = 7; - public static final int ACTION_OPEN_COPY_DESTINATION = 8; - - public static final int MODE_UNKNOWN = 0; - public static final int MODE_LIST = 1; - public static final int MODE_GRID = 2; - - public static final int SORT_ORDER_UNKNOWN = 0; - public static final int SORT_ORDER_DISPLAY_NAME = 1; - public static final int SORT_ORDER_LAST_MODIFIED = 2; - public static final int SORT_ORDER_SIZE = 3; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(action); - out.writeInt(userMode); - out.writeStringArray(acceptMimes); - out.writeInt(userSortOrder); - out.writeInt(allowMultiple ? 1 : 0); - out.writeInt(showSize ? 1 : 0); - out.writeInt(localOnly ? 1 : 0); - out.writeInt(forceAdvanced ? 1 : 0); - out.writeInt(showAdvanced ? 1 : 0); - out.writeInt(stackTouched ? 1 : 0); - out.writeInt(restored ? 1 : 0); - DurableUtils.writeToParcel(out, stack); - out.writeString(currentSearch); - out.writeMap(dirState); - out.writeList(selectedDocumentsForCopy); - out.writeList(excludedAuthorities); - } - - public static final Creator<State> CREATOR = new Creator<State>() { - @Override - public State createFromParcel(Parcel in) { - final State state = new State(); - state.action = in.readInt(); - state.userMode = in.readInt(); - state.acceptMimes = in.readStringArray(); - state.userSortOrder = in.readInt(); - state.allowMultiple = in.readInt() != 0; - state.showSize = in.readInt() != 0; - state.localOnly = in.readInt() != 0; - state.forceAdvanced = in.readInt() != 0; - state.showAdvanced = in.readInt() != 0; - state.stackTouched = in.readInt() != 0; - state.restored = in.readInt() != 0; - DurableUtils.readFromParcel(in, state.stack); - state.currentSearch = in.readString(); - in.readMap(state.dirState, null); - in.readList(state.selectedDocumentsForCopy, null); - in.readList(state.excludedAuthorities, null); - return state; - } - - @Override - public State[] newArray(int size) { - return new State[size]; - } - }; - } - void setDisplayAdvancedDevices(boolean display) { State state = getDisplayState(); LocalPreferences.setDisplayAdvancedDevices(this, display); @@ -562,7 +432,7 @@ abstract class BaseActivity extends Activity { return getDisplayState().stack.peek(); } - public Executor getCurrentExecutor() { + public Executor getExecutorForCurrentDirectory() { final DocumentInfo cwd = getCurrentDirectory(); if (cwd != null && cwd.authority != null) { return ProviderExecutor.forAuthority(cwd.authority); diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java index f8ec8f114313..815fbfe8e684 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java @@ -16,9 +16,11 @@ package com.android.documentsui; +import static com.android.documentsui.Shared.DEBUG; import static com.android.documentsui.model.DocumentInfo.getCursorLong; import static com.android.documentsui.model.DocumentInfo.getCursorString; +import android.app.Activity; import android.app.IntentService; import android.app.Notification; import android.app.NotificationManager; @@ -36,6 +38,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; +import android.support.design.widget.Snackbar; import android.text.format.DateUtils; import android.util.Log; import android.widget.Toast; @@ -56,7 +59,6 @@ import java.util.Objects; public class CopyService extends IntentService { public static final String TAG = "CopyService"; - public static final boolean DEBUG = false; private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL"; public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST"; @@ -107,10 +109,10 @@ public class CopyService extends IntentService { * @param srcDocs A list of src files to copy. * @param dstStack The copy destination stack. */ - public static void start(Context context, List<DocumentInfo> srcDocs, DocumentStack dstStack, + public static void start(Activity activity, List<DocumentInfo> srcDocs, DocumentStack dstStack, int mode) { - final Resources res = context.getResources(); - final Intent copyIntent = new Intent(context, CopyService.class); + final Resources res = activity.getResources(); + final Intent copyIntent = new Intent(activity, CopyService.class); copyIntent.putParcelableArrayListExtra( EXTRA_SRC_LIST, new ArrayList<DocumentInfo>(srcDocs)); copyIntent.putExtra(EXTRA_STACK, (Parcelable) dstStack); @@ -118,10 +120,10 @@ public class CopyService extends IntentService { int toastMessage = (mode == TRANSFER_MODE_COPY) ? R.plurals.copy_begin : R.plurals.move_begin; - Toast.makeText(context, + Shared.makeSnackbar(activity, res.getQuantityString(toastMessage, srcDocs.size(), srcDocs.size()), - Toast.LENGTH_SHORT).show(); - context.startService(copyIntent); + Snackbar.LENGTH_SHORT).show(); + activity.startService(copyIntent); } @Override diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java index e408e6eb821d..9f4451663706 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java @@ -32,6 +32,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; +import android.support.design.widget.Snackbar; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -39,7 +40,6 @@ import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; -import android.widget.Toast; import com.android.documentsui.model.DocumentInfo; @@ -147,7 +147,7 @@ public class CreateDirectoryFragment extends DialogFragment { // Navigate into newly created child mActivity.onDirectoryCreated(result); } else { - Toast.makeText(mActivity, R.string.create_error, Toast.LENGTH_SHORT).show(); + Shared.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show(); } mActivity.setPending(false); diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index 1a17b6c63997..3c6be6e47b11 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -16,15 +16,15 @@ package com.android.documentsui; -import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE; -import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE_ALL; -import static com.android.documentsui.BaseActivity.State.ACTION_CREATE; -import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE; -import static com.android.documentsui.BaseActivity.State.MODE_GRID; -import static com.android.documentsui.BaseActivity.State.MODE_LIST; -import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN; -import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN; +import static com.android.documentsui.Shared.DEBUG; import static com.android.documentsui.Shared.TAG; +import static com.android.documentsui.State.ACTION_BROWSE; +import static com.android.documentsui.State.ACTION_CREATE; +import static com.android.documentsui.State.ACTION_MANAGE; +import static com.android.documentsui.State.MODE_GRID; +import static com.android.documentsui.State.MODE_LIST; +import static com.android.documentsui.State.MODE_UNKNOWN; +import static com.android.documentsui.State.SORT_ORDER_UNKNOWN; import static com.android.documentsui.model.DocumentInfo.getCursorInt; import static com.android.documentsui.model.DocumentInfo.getCursorLong; import static com.android.documentsui.model.DocumentInfo.getCursorString; @@ -91,17 +91,14 @@ import android.view.ViewGroup; import android.view.ViewParent; import android.widget.ImageView; import android.widget.TextView; -import android.widget.Toast; import com.android.documentsui.BaseActivity.DocumentContext; -import com.android.documentsui.BaseActivity.State; import com.android.documentsui.MultiSelectManager.Selection; import com.android.documentsui.ProviderExecutor.Preemptable; import com.android.documentsui.RecentsProvider.StateColumns; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.RootInfo; -import com.android.internal.util.Preconditions; import com.google.common.collect.Lists; @@ -126,7 +123,6 @@ public class DirectoryFragment extends Fragment { public static final int REQUEST_COPY_DESTINATION = 1; private static final int LOADER_ID = 42; - private static final boolean DEBUG = false; private static final boolean DEBUG_ENABLE_DND = false; private static final String EXTRA_TYPE = "type"; @@ -369,21 +365,6 @@ public class DirectoryFragment extends Fragment { @Override public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) { - if (result == null || result.exception != null) { - // onBackPressed does a fragment transaction, which can't be done inside - // onLoadFinished - mHandler.post(new Runnable() { - @Override - public void run() { - final Activity activity = getActivity(); - if (activity != null) { - activity.onBackPressed(); - } - } - }); - return; - } - if (!isAdded()) return; mModel.update(result); @@ -631,7 +612,6 @@ public class DirectoryFragment extends Fragment { @Override public void onItemStateChanged(int position, boolean selected) { - final Cursor cursor = mModel.getItem(position); checkNotNull(cursor, "Cursor cannot be null."); @@ -717,8 +697,9 @@ public class DirectoryFragment extends Fragment { return true; } else if (id == R.id.menu_delete) { - deleteDocuments(selection); + // Exit selection mode first, so we avoid deselecting deleted documents. mode.finish(); + deleteDocuments(selection); return true; } else if (id == R.id.menu_copy_to) { @@ -727,8 +708,9 @@ public class DirectoryFragment extends Fragment { return true; } else if (id == R.id.menu_move_to) { - transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE); + // Exit selection mode first, so we avoid deselecting deleted documents. mode.finish(); + transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE); return true; } else if (id == R.id.menu_copy_to_clipboard) { @@ -822,8 +804,8 @@ public class DirectoryFragment extends Fragment { mModel.markForDeletion(selected); - Activity activity = getActivity(); - Snackbar.make(this.getView(), message, Snackbar.LENGTH_LONG) + final Activity activity = getActivity(); + Shared.makeSnackbar(activity, message, Snackbar.LENGTH_LONG) .setAction( R.string.undo, new android.view.View.OnClickListener() { @@ -838,11 +820,11 @@ public class DirectoryFragment extends Fragment { mModel.undoDeletion(); } else { mModel.finalizeDeletion( - new Runnable() { + new Model.DeletionListener() { @Override - public void run() { - Snackbar.make( - DirectoryFragment.this.getView(), + public void onError() { + Shared.makeSnackbar( + activity, R.string.toast_failed_delete, Snackbar.LENGTH_LONG) .show(); @@ -900,6 +882,29 @@ public class DirectoryFragment extends Fragment { } } + void showEmptyView() { + mEmptyView.setVisibility(View.VISIBLE); + mRecView.setVisibility(View.GONE); + TextView msg = (TextView) mEmptyView.findViewById(R.id.message); + msg.setText(R.string.empty); + // No retry button for the empty view. + mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE); + } + + void showErrorView() { + mEmptyView.setVisibility(View.VISIBLE); + mRecView.setVisibility(View.GONE); + TextView msg = (TextView) mEmptyView.findViewById(R.id.message); + msg.setText(R.string.query_error); + // TODO: Enable this once the retry button does something. + mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE); + } + + void showRecyclerView() { + mEmptyView.setVisibility(View.GONE); + mRecView.setVisibility(View.VISIBLE); + } + private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> { private final Context mContext; @@ -1239,9 +1244,11 @@ public class DirectoryFragment extends Fragment { private void copyDocuments(final List<DocumentInfo> docs, final DocumentInfo destination) { if (!canCopy(docs, destination)) { - Toast.makeText( + Shared.makeSnackbar( getActivity(), - R.string.clipboard_files_cannot_paste, Toast.LENGTH_SHORT).show(); + R.string.clipboard_files_cannot_paste, + Snackbar.LENGTH_SHORT) + .show(); return; } @@ -1291,10 +1298,10 @@ public class DirectoryFragment extends Fragment { void onDocumentsReady(List<DocumentInfo> docs) { mClipper.clipDocuments(docs); Activity activity = getActivity(); - Toast.makeText(activity, + Shared.makeSnackbar(activity, activity.getResources().getQuantityString( R.plurals.clipboard_files_clipped, docs.size(), docs.size()), - Toast.LENGTH_SHORT).show(); + Snackbar.LENGTH_SHORT).show(); } }.execute(items); } @@ -1554,9 +1561,9 @@ public class DirectoryFragment extends Fragment { } private FragmentTuner pickFragmentTuner(final State state) { - return state.action == ACTION_BROWSE_ALL + return state.action == ACTION_BROWSE ? new FilesTuner() - : new DefaultTuner(state); + : new DefaultTuner(state.action); } /** @@ -1593,15 +1600,14 @@ public class DirectoryFragment extends Fragment { */ private static final class DefaultTuner implements FragmentTuner { - private final State mState; + private final boolean mManaging; - public DefaultTuner(State state) { - mState = state; + public DefaultTuner(int action) { + mManaging = (action == ACTION_MANAGE); } @Override public void updateActionMenu(Menu menu, int dirType, boolean canDelete) { - Preconditions.checkState(mState.action != ACTION_BROWSE_ALL); final MenuItem open = menu.findItem(R.id.menu_open); final MenuItem share = menu.findItem(R.id.menu_share); @@ -1610,14 +1616,11 @@ public class DirectoryFragment extends Fragment { final MenuItem moveTo = menu.findItem(R.id.menu_move_to); final MenuItem copyToClipboard = menu.findItem(R.id.menu_copy_to_clipboard); - final boolean manageOrBrowse = (mState.action == ACTION_MANAGE - || mState.action == ACTION_BROWSE); - - open.setVisible(!manageOrBrowse); - share.setVisible(manageOrBrowse); - delete.setVisible(manageOrBrowse && canDelete); + open.setVisible(!mManaging); + share.setVisible(mManaging); + delete.setVisible(mManaging && canDelete); // Disable copying from the Recents view. - copyTo.setVisible(manageOrBrowse && dirType != TYPE_RECENT_OPEN); + copyTo.setVisible(mManaging && dirType != TYPE_RECENT_OPEN); moveTo.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false)); // Only shown in files mode. @@ -1634,6 +1637,7 @@ public class DirectoryFragment extends Fragment { private static final class FilesTuner implements FragmentTuner { @Override public void updateActionMenu(Menu menu, int dirType, boolean canDelete) { + menu.findItem(R.id.menu_share).setVisible(true); menu.findItem(R.id.menu_delete).setVisible(canDelete); menu.findItem(R.id.menu_copy_to_clipboard).setVisible(true); @@ -1861,9 +1865,9 @@ public class DirectoryFragment extends Fragment { * @param view The view which will be used to interact with the user (e.g. surfacing * snackbars) for errors, info, etc. */ - void finalizeDeletion(Runnable errorCallback) { + void finalizeDeletion(DeletionListener listener) { final ContentResolver resolver = mContext.getContentResolver(); - DeleteFilesTask task = new DeleteFilesTask(resolver, errorCallback); + DeleteFilesTask task = new DeleteFilesTask(resolver, listener); task.execute(); } @@ -1873,16 +1877,16 @@ public class DirectoryFragment extends Fragment { */ private class DeleteFilesTask extends AsyncTask<Void, Void, List<DocumentInfo>> { private ContentResolver mResolver; - private Runnable mErrorCallback; + private DeletionListener mListener; /** * @param resolver A ContentResolver for performing the actual file deletions. * @param errorCallback A Runnable that is executed in the event that one or more errors * occured while copying files. Execution will occur on the UI thread. */ - public DeleteFilesTask(ContentResolver resolver, Runnable errorCallback) { + public DeleteFilesTask(ContentResolver resolver, DeletionListener listener) { mResolver = resolver; - mErrorCallback = errorCallback; + mListener = listener; } @Override @@ -1916,15 +1920,29 @@ public class DirectoryFragment extends Fragment { if (hadTrouble) { // TODO show which files failed? b/23720103 - mErrorCallback.run(); + mListener.onError(); if (DEBUG) Log.d(TAG, "Deletion task completed. Some deletions failed."); } else { if (DEBUG) Log.d(TAG, "Deletion task completed successfully."); } mMarkedForDeletion.clear(); + + mListener.onCompletion(); } } + static class DeletionListener { + /** + * Called when deletion has completed (regardless of whether an error occurred). + */ + void onCompletion() {} + + /** + * Called at the end of a deletion operation that produced one or more errors. + */ + void onError() {} + } + void addUpdateListener(UpdateListener listener) { checkState(mUpdateListener == null); mUpdateListener = listener; @@ -1955,21 +1973,16 @@ public class DirectoryFragment extends Fragment { mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE); if (model.isEmpty()) { - mEmptyView.setVisibility(View.VISIBLE); - mRecView.setVisibility(View.GONE); + showEmptyView(); } else { - mEmptyView.setVisibility(View.GONE); - mRecView.setVisibility(View.VISIBLE); + showRecyclerView(); + mAdapter.notifyDataSetChanged(); } - - mAdapter.notifyDataSetChanged(); } @Override public void onModelUpdateFailed(Exception e) { - // TODO: deal with catastrophic update failures - String error = getString(R.string.query_error); - mAdapter.notifyDataSetChanged(); + showErrorView(); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java index 0edb2413b0ca..bb82b386aa12 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java @@ -16,12 +16,12 @@ package com.android.documentsui; -import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN; -import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME; -import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED; -import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE; -import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN; import static com.android.documentsui.Shared.TAG; +import static com.android.documentsui.State.MODE_UNKNOWN; +import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME; +import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED; +import static com.android.documentsui.State.SORT_ORDER_SIZE; +import static com.android.documentsui.State.SORT_ORDER_UNKNOWN; import static com.android.documentsui.model.DocumentInfo.getCursorInt; import android.content.AsyncTaskLoader; @@ -37,7 +37,6 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.util.Log; -import com.android.documentsui.BaseActivity.State; import com.android.documentsui.RecentsProvider.StateColumns; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.RootInfo; diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java index 4893652c4849..000b92a0b1a5 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java @@ -18,9 +18,9 @@ package com.android.documentsui; import android.content.Context; import android.util.AttributeSet; -import android.widget.FrameLayout; +import android.widget.LinearLayout; -public class DirectoryView extends FrameLayout { +public class DirectoryView extends LinearLayout { private float mPosition = 0f; private int mWidth; diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index 8b2b4f2dc6ae..f6ded4b7df5a 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -16,19 +16,16 @@ package com.android.documentsui; -import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE; -import static com.android.documentsui.BaseActivity.State.ACTION_CREATE; -import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION; -import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE; -import static com.android.documentsui.DirectoryFragment.ANIM_DOWN; import static com.android.documentsui.DirectoryFragment.ANIM_NONE; +import static com.android.documentsui.State.ACTION_CREATE; +import static com.android.documentsui.State.ACTION_GET_CONTENT; +import static com.android.documentsui.State.ACTION_OPEN; +import static com.android.documentsui.State.ACTION_OPEN_COPY_DESTINATION; +import static com.android.documentsui.State.ACTION_OPEN_TREE; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; -import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ComponentName; import android.content.ContentProviderClient; @@ -44,7 +41,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Parcelable; import android.provider.DocumentsContract; -import android.provider.DocumentsContract.Root; +import android.support.design.widget.Snackbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -52,7 +49,6 @@ import android.view.View; import android.view.WindowManager; import android.widget.BaseAdapter; import android.widget.Spinner; -import android.widget.Toast; import android.widget.Toolbar; import com.android.documentsui.RecentsProvider.RecentColumns; @@ -87,7 +83,7 @@ public class DocumentsActivity extends BaseActivity { super.onCreate(icicle); final Resources res = getResources(); - mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_BROWSE; + mShowAsDialog = res.getBoolean(R.bool.show_as_dialog); if (!mShowAsDialog) { setTheme(R.style.DocumentsNonDialogTheme); @@ -123,14 +119,6 @@ public class DocumentsActivity extends BaseActivity { setActionBar(mToolbar); - // Hide roots when we're managing a specific root - if (mState.action == ACTION_BROWSE) { - mDrawer.lockClosed(); - if (mShowAsDialog) { - findViewById(R.id.container_roots).setVisibility(View.GONE); - } - } - if (mState.action == ACTION_CREATE) { final String mimeType = getIntent().getType(); final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE); @@ -156,12 +144,7 @@ public class DocumentsActivity extends BaseActivity { // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent // talkback from reading aloud the default title, we clear it here. setTitle(""); - if (mState.action == ACTION_BROWSE) { - final Uri rootUri = getIntent().getData(); - new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor()); - } else { - new RestoreStackTask().execute(); - } + new RestoreStackTask().execute(); } else { onCurrentDirectoryChanged(ANIM_NONE); } @@ -181,8 +164,6 @@ public class DocumentsActivity extends BaseActivity { state.action = ACTION_GET_CONTENT; } else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) { state.action = ACTION_OPEN_TREE; - } else if (DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT.equals(action)) { - state.action = ACTION_BROWSE; } else if (DocumentsIntent.ACTION_OPEN_COPY_DESTINATION.equals(action)) { state.action = ACTION_OPEN_COPY_DESTINATION; } @@ -192,20 +173,6 @@ public class DocumentsActivity extends BaseActivity { Intent.EXTRA_ALLOW_MULTIPLE, false); } - if (state.action == ACTION_BROWSE) { - state.acceptMimes = new String[] { "*/*" }; - state.allowMultiple = true; - } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { - state.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); - } else { - state.acceptMimes = new String[] { intent.getType() }; - } - - if (state.action == ACTION_BROWSE) { - state.showSize = true; - } else { - state.showSize = LocalPreferences.getDisplayFileSize(this); - } if (state.action == ACTION_OPEN_COPY_DESTINATION) { state.directoryCopy = intent.getBooleanExtra( BaseActivity.DocumentsIntent.EXTRA_DIRECTORY_COPY, false); @@ -357,11 +324,7 @@ public class DocumentsActivity extends BaseActivity { final MenuItem fileSize = menu.findItem(R.id.menu_file_size); final MenuItem settings = menu.findItem(R.id.menu_settings); - // File size is locked visible for browse because that is the action triggered by Settings, - // where the user is trying to find large files to clean up. - // TODO: instead of setting this according to the action, use a local preference, but - // provide a @hide extra to let callers like Settings force-enable size visibility. - boolean fileSizeVisible = mState.action != ACTION_BROWSE; + boolean fileSizeVisible = mState.showSize && !mState.forceSize; if (mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE || mState.action == ACTION_OPEN_COPY_DESTINATION) { @@ -383,11 +346,9 @@ public class DocumentsActivity extends BaseActivity { createDir.setVisible(false); } - advanced.setVisible(mState.action != ACTION_BROWSE && !mState.forceAdvanced); + advanced.setVisible(!mState.forceAdvanced); fileSize.setVisible(fileSizeVisible); - - settings.setVisible(mState.action == ACTION_BROWSE - && (root.flags & Root.FLAG_HAS_SETTINGS) != 0); + settings.setVisible(false); return true; } @@ -446,11 +407,11 @@ public class DocumentsActivity extends BaseActivity { } void onSaveRequested(DocumentInfo replaceTarget) { - new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor()); + new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory()); } void onSaveRequested(String mimeType, String displayName) { - new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor()); + new CreateFinishTask(mimeType, displayName).executeOnExecutor(getExecutorForCurrentDirectory()); } @Override @@ -466,21 +427,10 @@ public class DocumentsActivity extends BaseActivity { openDirectory(doc); } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) { // Explicit file picked, return - new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getCurrentExecutor()); + new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory()); } else if (mState.action == ACTION_CREATE) { // Replace selected file SaveFragment.get(fm).setReplaceTarget(doc); - } else if (mState.action == ACTION_BROWSE) { - // Go straight to viewing - final Intent view = new Intent(Intent.ACTION_VIEW); - view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - view.setData(doc.derivedUri); - - try { - startActivity(view); - } catch (ActivityNotFoundException ex) { - Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); - } } } @@ -492,7 +442,7 @@ public class DocumentsActivity extends BaseActivity { for (int i = 0; i < size; i++) { uris[i] = docs.get(i).derivedUri; } - new ExistingFinishTask(uris).executeOnExecutor(getCurrentExecutor()); + new ExistingFinishTask(uris).executeOnExecutor(getExecutorForCurrentDirectory()); } } @@ -507,7 +457,7 @@ public class DocumentsActivity extends BaseActivity { // Should not be reached. throw new IllegalStateException("Invalid mState.action."); } - new PickFinishTask(result).executeOnExecutor(getCurrentExecutor()); + new PickFinishTask(result).executeOnExecutor(getExecutorForCurrentDirectory()); } @Override @@ -661,8 +611,8 @@ public class DocumentsActivity extends BaseActivity { if (result != null) { onTaskFinished(result); } else { - Toast.makeText(DocumentsActivity.this, R.string.save_error, Toast.LENGTH_SHORT) - .show(); + Shared.makeSnackbar( + DocumentsActivity.this, R.string.save_error, Snackbar.LENGTH_SHORT).show(); } setPending(false); diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java index c1362c87e620..df803fbc4bb2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java @@ -16,8 +16,10 @@ package com.android.documentsui; -import static com.android.documentsui.DirectoryFragment.ANIM_DOWN; import static com.android.documentsui.DirectoryFragment.ANIM_NONE; +import static com.android.documentsui.Shared.DEBUG; +import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.internal.util.Preconditions.checkState; import android.app.Activity; import android.app.FragmentManager; @@ -25,12 +27,11 @@ import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ContentResolver; import android.content.ContentValues; -import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.provider.DocumentsContract; import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; @@ -38,7 +39,6 @@ import android.view.MenuItem; import android.view.View; import android.widget.BaseAdapter; import android.widget.Spinner; -import android.widget.Toast; import android.widget.Toolbar; import com.android.documentsui.RecentsProvider.ResumeColumns; @@ -46,7 +46,6 @@ import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; -import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.Arrays; @@ -58,7 +57,6 @@ import java.util.List; public class FilesActivity extends BaseActivity { public static final String TAG = "FilesActivity"; - static final boolean DEBUG = false; private Toolbar mToolbar; private Spinner mToolbarStack; @@ -74,8 +72,6 @@ public class FilesActivity extends BaseActivity { public void onCreate(Bundle icicle) { super.onCreate(icicle); - final Context context = this; - mToolbar = (Toolbar) findViewById(R.id.toolbar); mStackAdapter = new StackAdapter(); @@ -90,10 +86,19 @@ public class FilesActivity extends BaseActivity { RootsFragment.show(getFragmentManager(), null); if (!mState.restored) { - new RestoreStackTask().execute(); + Intent intent = getIntent(); + Uri rootUri = intent.getData(); + + // If we've got a specific root to display, restore that root using a dedicated + // authority. That way a misbehaving provider won't result in an ANR. + if (rootUri != null && !LauncherActivity.isLaunchUri(rootUri)) { + new RestoreRootTask(rootUri).executeOnExecutor( + ProviderExecutor.forAuthority(rootUri.getAuthority())); + } else { + new RestoreStackTask().execute(); + } // Show a failure dialog if there was a failed operation. - final Intent intent = getIntent(); final DocumentStack dstStack = intent.getParcelableExtra(CopyService.EXTRA_STACK); final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0); final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE, @@ -115,22 +120,16 @@ public class FilesActivity extends BaseActivity { final Intent intent = getIntent(); - state.action = State.ACTION_BROWSE_ALL; - state.acceptMimes = new String[] { intent.getType() }; + state.action = State.ACTION_BROWSE; state.allowMultiple = true; - // These options are specific to the DocumentsActivity. - Preconditions.checkArgument( - !intent.hasExtra(Intent.EXTRA_LOCAL_ONLY)); - Preconditions.checkArgument( - !intent.hasExtra(DocumentsContract.EXTRA_SHOW_ADVANCED)); - - state.showAdvanced = LocalPreferences.getDisplayAdvancedDevices(this); - state.showSize = LocalPreferences.getDisplayFileSize(this); + // Options specific to the DocumentsActivity. + checkArgument(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY)); final DocumentStack stack = intent.getParcelableExtra(CopyService.EXTRA_STACK); - if (stack != null) + if (stack != null) { state.stack = stack; + } return state; } @@ -142,6 +141,21 @@ public class FilesActivity extends BaseActivity { } @Override + public void onResume() { + super.onResume(); + + final RootInfo root = getCurrentRoot(); + + // If we're browsing a specific root, and that root went away, then we + // have no reason to hang around. + // TODO: Rather than just disappearing, maybe we should inform + // the user what has happened, let them close us. Less surprising. + if (mRoots.getRootBlocking(root.authority, root.rootId) == null) { + finish(); + } + } + + @Override public void updateActionBar() { final RootInfo root = getCurrentRoot(); @@ -197,17 +211,22 @@ public class FilesActivity extends BaseActivity { menu.findItem(R.id.menu_file_size).setVisible(true); menu.findItem(R.id.menu_advanced).setVisible(true); - final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard); final MenuItem createDir = menu.findItem(R.id.menu_create_dir); - final MenuItem settings = menu.findItem(R.id.menu_settings); + final MenuItem newWindow = menu.findItem(R.id.menu_new_window); + final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard); boolean canCreateDir = canCreateDirectory(); createDir.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); createDir.setVisible(canCreateDir); + createDir.setEnabled(canCreateDir); + + newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + newWindow.setVisible(mProductivityDevice); + newWindow.setEnabled(mProductivityDevice); - pasteFromCb.setVisible(true); pasteFromCb.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + pasteFromCb.setVisible(true); pasteFromCb.setEnabled(mClipper.hasItemsToPaste()); return shown; @@ -215,12 +234,19 @@ public class FilesActivity extends BaseActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { - final int id = item.getItemId(); - if (id == R.id.menu_paste_from_clipboard) { - DirectoryFragment dir = DirectoryFragment.get(getFragmentManager()); - dir = DirectoryFragment.get(getFragmentManager()); - dir.pasteFromClipboard(); - return true; + switch (item.getItemId()) { + case R.id.menu_create_dir: + checkState(canCreateDirectory()); + showCreateDirectoryDialog(); + return true; + case R.id.menu_new_window: + startActivity(LauncherActivity.createLaunchIntent(this)); + return true; + case R.id.menu_paste_from_clipboard: + DirectoryFragment dir = DirectoryFragment.get(getFragmentManager()); + dir = DirectoryFragment.get(getFragmentManager()); + dir.pasteFromClipboard(); + return true; } return super.onOptionsItemSelected(item); @@ -296,7 +322,7 @@ public class FilesActivity extends BaseActivity { try { startActivity(intent); } catch (ActivityNotFoundException ex2) { - Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); + Shared.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show(); } } @@ -308,19 +334,13 @@ public class FilesActivity extends BaseActivity { dir = DirectoryFragment.get(getFragmentManager()); dir.selectAllFiles(); return true; - case KeyEvent.KEYCODE_N: - if (event.isShiftPressed() && canCreateDirectory()) { - showCreateDirectoryDialog(); - return true; - } case KeyEvent.KEYCODE_C: // TODO: Should be statically bound using alphabeticShortcut. See b/21330356. dir = DirectoryFragment.get(getFragmentManager()); dir.copySelectedToClipboard(); - // TODO: Cancel action mode in directory fragment. } - return super.onKeyUp(keyCode, event); + return super.onKeyShortcut(keyCode, event); } @Override diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java index ec1cb1de5c57..a1213d210b50 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java +++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java @@ -222,7 +222,7 @@ public class IconUtils { return context.getDrawable(R.drawable.ic_doc_album); } - if (mode == BaseActivity.State.MODE_GRID) { + if (mode == State.MODE_GRID) { return context.getDrawable(R.drawable.ic_grid_folder); } else { return context.getDrawable(R.drawable.ic_doc_folder); diff --git a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java new file mode 100644 index 000000000000..c29937d68cdf --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.documentsui; + +import android.app.Activity; +import android.app.ActivityManager; +import android.app.ActivityManager.AppTask; +import android.app.ActivityManager.RecentTaskInfo; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.Nullable; + +import java.util.List; + +/** + * Provides FilesActivity task grouping support. This allows multiple FilesActivities to be + * launched (a behavior imparted by way of {@code documentLaunchMode="intoExisting"} and + * our use of pseudo document {@link Uri}s. This also lets us move an existing task + * to the foreground when a suitable task exists. + * + * Requires that {@code documentLaunchMode="intoExisting"} be set on target activity. + * + */ +public class LauncherActivity extends Activity { + + public static final String LAUNCH_CONTROL_AUTHORITY = "com.android.documentsui.launchControl"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ActivityManager activities = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + List<AppTask> tasks = activities.getAppTasks(); + + AppTask raiseTask = null; + for (AppTask task : tasks) { + Uri taskUri = task.getTaskInfo().baseIntent.getData(); + if (taskUri != null && isLaunchUri(taskUri)) { + raiseTask = task; + } + } + + if (raiseTask == null) { + launchFilesTask(); + } else { + raiseFilesTask(activities, raiseTask.getTaskInfo()); + } + + finish(); + } + + private void launchFilesTask() { + Intent intent = createLaunchIntent(this); + startActivity(intent); + } + + private void raiseFilesTask(ActivityManager activities, RecentTaskInfo task) { + activities.moveTaskToFront(task.id, 0); + } + + static Intent createLaunchIntent(Context context) { + Intent intent = new Intent(context, FilesActivity.class); + intent.setData(buildLaunchUri()); + return intent; + } + + private static Uri buildLaunchUri() { + return new Uri.Builder() + .authority(LAUNCH_CONTROL_AUTHORITY) + .fragment(String.valueOf(System.currentTimeMillis())) + .build(); + } + + static boolean isLaunchUri(@Nullable Uri uri) { + return uri != null && LAUNCH_CONTROL_AUTHORITY.equals(uri.getAuthority()); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java index 798992b470e3..ed7333d31149 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java @@ -16,9 +16,8 @@ package com.android.documentsui; -import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE; -import static com.android.documentsui.DirectoryFragment.ANIM_DOWN; import static com.android.documentsui.DirectoryFragment.ANIM_NONE; +import static com.android.documentsui.State.ACTION_MANAGE; import android.app.Activity; import android.app.Fragment; @@ -32,12 +31,12 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.provider.DocumentsContract; +import android.support.design.widget.Snackbar; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.BaseAdapter; import android.widget.Spinner; -import android.widget.Toast; import android.widget.Toolbar; import com.android.documentsui.RecentsProvider.ResumeColumns; @@ -87,7 +86,7 @@ public class ManageRootActivity extends BaseActivity { // talkback from reading aloud the default title, we clear it here. setTitle(""); final Uri rootUri = getIntent().getData(); - new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor()); + new RestoreRootTask(rootUri).executeOnExecutor(getExecutorForCurrentDirectory()); } else { onCurrentDirectoryChanged(ANIM_NONE); } @@ -185,7 +184,8 @@ public class ManageRootActivity extends BaseActivity { try { startActivity(view); } catch (ActivityNotFoundException ex2) { - Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show(); + Shared.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT) + .show(); } } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java index 583994351a0c..858fb423fe06 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java +++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java @@ -365,8 +365,8 @@ public final class MultiSelectManager { // To make this more correct, we'd need to update the Ranger class to return // information about what has changed. notifySelectionChanged(); - } else if (toggleSelection(input.getItemPosition())) { - notifySelectionChanged(); + } else { + toggleSelection(input.getItemPosition()); } } @@ -375,14 +375,13 @@ public final class MultiSelectManager { * a new Ranger (range selection manager) at that point is created. * * @param position - * @return True if state changed. */ - private boolean toggleSelection(int position) { + private void toggleSelection(int position) { // Position may be special "no position" during certain // transitional phases. If so, skip handling of the event. if (position == RecyclerView.NO_POSITION) { if (DEBUG) Log.d(TAG, "Ignoring toggle for element with no position."); - return false; + return; } boolean changed = false; @@ -391,7 +390,7 @@ public final class MultiSelectManager { } else { boolean canSelect = notifyBeforeItemStateChange(position, true); if (!canSelect) { - return false; + return; } if (mSingleSelect && !mSelection.isEmpty()) { clearSelectionQuietly(); @@ -407,7 +406,9 @@ public final class MultiSelectManager { changed = true; } - return changed; + if (changed) { + notifySelectionChanged(); + } } /** diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java index 5f6a5e90e2c7..48e28dcfdd5c 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java @@ -21,7 +21,6 @@ import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.os.Bundle; -import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -29,8 +28,6 @@ import android.widget.Button; import com.android.documentsui.model.DocumentInfo; -import java.util.Locale; - /** * Display pick confirmation bar, usually for selecting a directory. */ @@ -93,7 +90,7 @@ public class PickFragment extends Fragment { }; /** - * @param action Which action defined in BaseActivity.State is the picker shown for. + * @param action Which action defined in State is the picker shown for. */ public void setPickTarget(int action, int transferMode, DocumentInfo pickTarget) { mAction = action; @@ -109,11 +106,11 @@ public class PickFragment extends Fragment { */ private void updateView() { switch (mAction) { - case BaseActivity.State.ACTION_OPEN_TREE: + case State.ACTION_OPEN_TREE: mPick.setText(R.string.button_select); mCancel.setVisibility(View.GONE); break; - case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION: + case State.ACTION_OPEN_COPY_DESTINATION: mPick.setText(R.string.button_copy); mCancel.setVisibility(View.VISIBLE); break; @@ -123,7 +120,7 @@ public class PickFragment extends Fragment { } if (mPickTarget != null && ( - mAction == BaseActivity.State.ACTION_OPEN_TREE || + mAction == State.ACTION_OPEN_TREE || mPickTarget.isCreateSupported())) { mContainer.setVisibility(View.VISIBLE); } else { diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java index 4685c41fc2b6..607cb951bf3f 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java +++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java @@ -16,6 +16,8 @@ package com.android.documentsui; +import static com.android.documentsui.Shared.DEBUG; +import static com.android.documentsui.Shared.TAG; import static com.android.documentsui.model.DocumentInfo.getCursorString; import android.content.ClipData; @@ -38,9 +40,6 @@ import com.android.documentsui.model.DocumentInfo; */ final class QuickViewIntentBuilder { - private static final String TAG = "QvIntentBuilder"; - private static final boolean DEBUG = false; - private final DocumentInfo mDocument; private final DocumentContext mContext; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java index 1a7095a054c3..c2b64fb4317e 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java @@ -16,8 +16,9 @@ package com.android.documentsui; -import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED; +import static com.android.documentsui.Shared.DEBUG; import static com.android.documentsui.Shared.TAG; +import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED; import android.app.ActivityManager; import android.content.AsyncTaskLoader; @@ -34,7 +35,6 @@ import android.provider.DocumentsContract.Root; import android.text.format.DateUtils; import android.util.Log; -import com.android.documentsui.BaseActivity.State; import com.android.documentsui.model.RootInfo; import com.google.common.util.concurrent.AbstractFuture; @@ -53,8 +53,6 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; public class RecentLoader extends AsyncTaskLoader<DirectoryResult> { - private static final boolean DEBUG = false; - // TODO: clean up cursor ownership so background thread doesn't traverse // previously returned cursors for filtering/sorting; this currently races // with the UI thread. diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java index 681133156dca..cf682fa508fc 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java @@ -45,7 +45,6 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import com.android.documentsui.BaseActivity.State; import com.android.documentsui.RecentsProvider.RecentColumns; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java index f6e434966a8a..82eb732002bb 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java @@ -39,6 +39,7 @@ import android.util.Log; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; import com.android.internal.util.Predicate; + import com.google.android.collect.Sets; import libcore.io.IoUtils; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java index 05f7d8dd11e3..de35cef6ddb6 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java @@ -16,6 +16,7 @@ package com.android.documentsui; +import static com.android.documentsui.Shared.DEBUG; import static com.android.documentsui.Shared.TAG; import android.content.ContentProviderClient; @@ -34,12 +35,11 @@ import android.os.Handler; import android.os.SystemClock; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Root; +import android.support.annotation.VisibleForTesting; import android.util.Log; -import com.android.documentsui.BaseActivity.State; import com.android.documentsui.model.RootInfo; import com.android.internal.annotations.GuardedBy; -import android.support.annotation.VisibleForTesting; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; @@ -58,8 +58,6 @@ import java.util.concurrent.TimeUnit; * Cache of known storage backends and their roots. */ public class RootsCache { - private static final boolean LOGD = false; - public static final Uri sNotificationUri = Uri.parse( "content://com.android.documentsui.roots/"); @@ -91,7 +89,7 @@ public class RootsCache { @Override public void onChange(boolean selfChange, Uri uri) { - if (LOGD) Log.d(TAG, "Updating roots due to change at " + uri); + if (DEBUG) Log.d(TAG, "Updating roots due to change at " + uri); updateAuthorityAsync(uri.getAuthority()); } } @@ -148,7 +146,7 @@ public class RootsCache { final ContentResolver resolver = mContext.getContentResolver(); synchronized (mLock) { for (String authority : mStoppedAuthorities) { - if (LOGD) Log.d(TAG, "Loading stopped authority " + authority); + if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority); mRoots.putAll(authority, loadRootsForAuthority(resolver, authority)); } mStoppedAuthorities.clear(); @@ -199,7 +197,8 @@ public class RootsCache { } final long delta = SystemClock.elapsedRealtime() - start; - Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms"); + if (DEBUG) + Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms"); synchronized (mLock) { mRoots = mTaskRoots; mStoppedAuthorities = mTaskStoppedAuthorities; @@ -213,7 +212,7 @@ public class RootsCache { // Ignore stopped packages for now; we might query them // later during UI interaction. if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) { - if (LOGD) Log.d(TAG, "Ignoring stopped authority " + info.authority); + if (DEBUG) Log.d(TAG, "Ignoring stopped authority " + info.authority); mTaskStoppedAuthorities.add(info.authority); return; } @@ -223,7 +222,7 @@ public class RootsCache { if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) { synchronized (mLock) { if (mTaskRoots.putAll(info.authority, mRoots.get(info.authority))) { - if (LOGD) Log.d(TAG, "Used cached roots for " + info.authority); + if (DEBUG) Log.d(TAG, "Used cached roots for " + info.authority); cacheHit = true; } } @@ -241,7 +240,7 @@ public class RootsCache { * Bring up requested provider and query for all active roots. */ private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority) { - if (LOGD) Log.d(TAG, "Loading roots for " + authority); + if (DEBUG) Log.d(TAG, "Loading roots for " + authority); synchronized (mObservedAuthorities) { if (mObservedAuthorities.add(authority)) { @@ -370,10 +369,13 @@ public class RootsCache { // Exclude downloads roots that don't support directory creation // TODO: Add flag to check the root supports directory creation or not. if (state.directoryCopy && root.isDownloads()) continue; - // Only show empty roots when creating - if ((state.action != State.ACTION_CREATE || - state.action != State.ACTION_OPEN_TREE || - state.action != State.ACTION_OPEN_COPY_DESTINATION) && empty) continue; + + // Only show empty roots when creating, or in browse mode. + if (empty && (state.action == State.ACTION_OPEN + || state.action == State.ACTION_GET_CONTENT)) { + if (DEBUG) Log.i(TAG, "Skipping empty root: " + root); + continue; + } // Only include roots that serve requested content final boolean overlap = @@ -385,7 +387,7 @@ public class RootsCache { // Exclude roots from the calling package. if (state.excludedAuthorities.contains(root.authority)) { - if (LOGD) Log.d(TAG, "Excluding root " + root.authority + " from calling package."); + if (DEBUG) Log.d(TAG, "Excluding root " + root.authority + " from calling package."); continue; } diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java index c02184b72b2f..c98da471cd88 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java @@ -41,7 +41,6 @@ import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; -import com.android.documentsui.BaseActivity.State; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.RootInfo; diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java index 49651b4dc50b..c81377a19aa2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java @@ -19,7 +19,6 @@ package com.android.documentsui; import android.content.AsyncTaskLoader; import android.content.Context; -import com.android.documentsui.BaseActivity.State; import com.android.documentsui.model.RootInfo; import java.util.Collection; diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java index 0c1ebc16f1df..29bcd240a1b8 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java +++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java @@ -16,13 +16,18 @@ package com.android.documentsui; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.app.Activity; import android.content.Context; +import android.support.design.widget.Snackbar; +import android.view.View; /** * @hide */ public final class Shared { - public static final boolean DEBUG = false; + public static final boolean DEBUG = true; public static final String TAG = "Documents"; /** @@ -31,4 +36,14 @@ public final class Shared { public static final String getQuantityString(Context context, int resourceId, int quantity) { return context.getResources().getQuantityString(resourceId, quantity, quantity); } + + public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) { + return makeSnackbar(activity, activity.getResources().getText(messageId), duration); + } + + public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration) + { + final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout)); + return Snackbar.make(view, message, duration); + } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java index 3ec3d1c01062..6698ff159f25 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java +++ b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java @@ -16,9 +16,9 @@ package com.android.documentsui; -import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME; -import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED; -import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE; +import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME; +import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED; +import static com.android.documentsui.State.SORT_ORDER_SIZE; import static com.android.documentsui.model.DocumentInfo.getCursorLong; import static com.android.documentsui.model.DocumentInfo.getCursorString; diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java new file mode 100644 index 000000000000..4306a0e024a2 --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/State.java @@ -0,0 +1,153 @@ +/* + * 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.documentsui; + +import android.content.Intent; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.SparseArray; + +import com.android.documentsui.model.DocumentInfo; +import com.android.documentsui.model.DocumentStack; +import com.android.documentsui.model.DurableUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class State implements android.os.Parcelable { + public int action; + public String[] acceptMimes; + + /** Explicit user choice */ + public int userMode = MODE_UNKNOWN; + /** Derived after loader */ + public int derivedMode = MODE_LIST; + + /** Explicit user choice */ + public int userSortOrder = SORT_ORDER_UNKNOWN; + /** Derived after loader */ + public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME; + + public boolean allowMultiple; + public boolean forceSize; + public boolean showSize; + public boolean localOnly; + public boolean forceAdvanced; + public boolean showAdvanced; + public boolean stackTouched; + public boolean restored; + public boolean directoryCopy; + /** Transfer mode for file copy/move operations. */ + public int transferMode; + + /** Current user navigation stack; empty implies recents. */ + public DocumentStack stack = new DocumentStack(); + /** Currently active search, overriding any stack. */ + public String currentSearch; + + /** Instance state for every shown directory */ + public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>(); + + /** Currently copying file */ + public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>(); + + /** Name of the package that started DocsUI */ + public List<String> excludedAuthorities = new ArrayList<>(); + + public static final int ACTION_OPEN = 1; + public static final int ACTION_CREATE = 2; + public static final int ACTION_GET_CONTENT = 3; + public static final int ACTION_OPEN_TREE = 4; + public static final int ACTION_MANAGE = 5; + public static final int ACTION_BROWSE = 6; + public static final int ACTION_OPEN_COPY_DESTINATION = 8; + + public static final int MODE_UNKNOWN = 0; + public static final int MODE_LIST = 1; + public static final int MODE_GRID = 2; + + public static final int SORT_ORDER_UNKNOWN = 0; + public static final int SORT_ORDER_DISPLAY_NAME = 1; + public static final int SORT_ORDER_LAST_MODIFIED = 2; + public static final int SORT_ORDER_SIZE = 3; + + public void initAcceptMimes(Intent intent) { + if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { + acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); + } else { + String glob = intent.getType(); + acceptMimes = new String[] { glob != null ? glob : "*/*" }; + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(action); + out.writeInt(userMode); + out.writeStringArray(acceptMimes); + out.writeInt(userSortOrder); + out.writeInt(allowMultiple ? 1 : 0); + out.writeInt(forceSize ? 1 : 0); + out.writeInt(showSize ? 1 : 0); + out.writeInt(localOnly ? 1 : 0); + out.writeInt(forceAdvanced ? 1 : 0); + out.writeInt(showAdvanced ? 1 : 0); + out.writeInt(stackTouched ? 1 : 0); + out.writeInt(restored ? 1 : 0); + DurableUtils.writeToParcel(out, stack); + out.writeString(currentSearch); + out.writeMap(dirState); + out.writeList(selectedDocumentsForCopy); + out.writeList(excludedAuthorities); + } + + public static final Creator<State> CREATOR = new Creator<State>() { + @Override + public State createFromParcel(Parcel in) { + final State state = new State(); + state.action = in.readInt(); + state.userMode = in.readInt(); + state.acceptMimes = in.readStringArray(); + state.userSortOrder = in.readInt(); + state.allowMultiple = in.readInt() != 0; + state.forceSize = in.readInt() != 0; + state.showSize = in.readInt() != 0; + state.localOnly = in.readInt() != 0; + state.forceAdvanced = in.readInt() != 0; + state.showAdvanced = in.readInt() != 0; + state.stackTouched = in.readInt() != 0; + state.restored = in.readInt() != 0; + DurableUtils.readFromParcel(in, state.stack); + state.currentSearch = in.readString(); + in.readMap(state.dirState, null); + in.readList(state.selectedDocumentsForCopy, null); + in.readList(state.excludedAuthorities, null); + return state; + } + + @Override + public State[] newArray(int size) { + return new State[size]; + } + }; +}
\ No newline at end of file diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java index 1895a6e66450..98ffb77c4cd6 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java @@ -34,6 +34,9 @@ import com.android.documentsui.MultiSelectManager.Selection; import com.android.documentsui.model.DocumentInfo; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + public class DirectoryFragmentModelTest extends AndroidTestCase { @@ -77,14 +80,6 @@ public class DirectoryFragmentModelTest extends AndroidTestCase { delete(2, 4); assertEquals(ITEM_COUNT - 2, model.getItemCount()); - - // Finalize the deletion. Provide a callback that just ignores errors. - model.finalizeDeletion( - new Runnable() { - @Override - public void run() {} - }); - assertEquals(ITEM_COUNT - 2, model.getItemCount()); } // Tests that the item count is correct after a deletion is undone. @@ -95,7 +90,6 @@ public class DirectoryFragmentModelTest extends AndroidTestCase { // Undo the deletion model.undoDeletion(); assertEquals(ITEM_COUNT, model.getItemCount()); - } // Tests that the right things are marked for deletion. @@ -125,6 +119,15 @@ public class DirectoryFragmentModelTest extends AndroidTestCase { assertEquals("0", docs.get(0).documentId); assertEquals("1", docs.get(1).documentId); assertEquals("4", docs.get(2).documentId); + + TestDeletionListener testListener = new TestDeletionListener(); + model.finalizeDeletion(testListener); + testListener.waitForDone(); + + docs = getDocumentInfo(0, 1, 2); + assertEquals("0", docs.get(0).documentId); + assertEquals("1", docs.get(1).documentId); + assertEquals("2", docs.get(2).documentId); } // Tests that Model.getItem returns the right items after a deletion is undone. @@ -176,4 +179,20 @@ public class DirectoryFragmentModelTest extends AndroidTestCase { return null; } } + + private static class TestDeletionListener extends Model.DeletionListener { + final CountDownLatch mSignal = new CountDownLatch(1); + + @Override + public void onCompletion() { + mSignal.countDown(); + } + + public void waitForDone() { + try { + boolean timeout = mSignal.await(10, TimeUnit.SECONDS); + assertTrue("Timed out waiting for deletion completion", timeout); + } catch (InterruptedException e) {} + } + } } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java index 25d4ed4183f0..2447469f9c64 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.support.v7.widget.RecyclerView; +import android.test.AndroidTestCase; import android.util.SparseBooleanArray; import android.view.MotionEvent; import android.view.View; @@ -27,8 +28,6 @@ import android.view.ViewGroup; import com.android.documentsui.MultiSelectManager.Selection; -import org.junit.Before; -import org.junit.Test; import org.mockito.Mockito; import java.util.ArrayList; @@ -36,7 +35,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -public class MultiSelectManagerTest { +public class MultiSelectManagerTest extends AndroidTestCase { private static final List<String> items; static { @@ -54,7 +53,6 @@ public class MultiSelectManagerTest { private TestCallback mCallback; private EventHelper mEventHelper; - @Before public void setUp() throws Exception { mAdapter = new TestAdapter(items); mCallback = new TestCallback(); @@ -63,65 +61,61 @@ public class MultiSelectManagerTest { mManager.addCallback(mCallback); } - @Test - public void mouseClick_StartsSelectionMode() { + public void testMouseClick_StartsSelectionMode() { click(7); assertSelection(7); } - @Test - public void mouseClick_ShiftClickExtendsSelection() { + public void testMouseClick_NotifiesSelectionChanged() { + click(7); + mCallback.assertSelectionChanged(); + } + + public void testMouseClick_ShiftClickExtendsSelection() { longPress(7); shiftClick(11); assertRangeSelection(7, 11); } - @Test - public void mouseClick_NoPosition_ClearsSelection() { + public void testMouseClick_NoPosition_ClearsSelection() { longPress(7); click(11); click(RecyclerView.NO_POSITION); assertSelection(); } - @Test - public void setSelectionFocusBegin() { + public void testSetSelectionFocusBegin() { mManager.setItemSelected(7, true); mManager.setSelectionFocusBegin(7); shiftClick(11); assertRangeSelection(7, 11); } - @Test - public void longPress_StartsSelectionMode() { + public void testLongPress_StartsSelectionMode() { longPress(7); assertSelection(7); } - @Test - public void longPress_SecondPressExtendsSelection() { + public void testLongPress_SecondPressExtendsSelection() { longPress(7); longPress(99); assertSelection(7, 99); } - @Test - public void singleTapUp_UnselectsSelectedItem() { + public void testSingleTapUp_UnselectsSelectedItem() { longPress(7); tap(7); assertSelection(); } - @Test - public void singleTapUp_NoPosition_ClearsSelection() { + public void testSingleTapUp_NoPosition_ClearsSelection() { longPress(7); tap(11); tap(RecyclerView.NO_POSITION); assertSelection(); } - @Test - public void singleTapUp_ExtendsSelection() { + public void testSingleTapUp_ExtendsSelection() { longPress(99); tap(7); tap(13); @@ -129,30 +123,26 @@ public class MultiSelectManagerTest { assertSelection(7, 99, 13, 129899); } - @Test - public void singleTapUp_ShiftCreatesRangeSelection() { + public void testSingleTapUp_ShiftCreatesRangeSelection() { longPress(7); shiftTap(17); assertRangeSelection(7, 17); } - @Test - public void singleTapUp_ShiftCreatesRangeSeletion_Backwards() { + public void testSingleTapUp_ShiftCreatesRangeSeletion_Backwards() { longPress(17); shiftTap(7); assertRangeSelection(7, 17); } - @Test - public void singleTapUp_SecondShiftClickExtendsSelection() { + public void testSingleTapUp_SecondShiftClickExtendsSelection() { longPress(7); shiftTap(11); shiftTap(17); assertRangeSelection(7, 17); } - @Test - public void singleTapUp_MultipleContiguousRangesSelected() { + public void testSingleTapUp_MultipleContiguousRangesSelected() { longPress(7); shiftTap(11); tap(20); @@ -162,16 +152,14 @@ public class MultiSelectManagerTest { assertSelectionSize(11); } - @Test - public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick() { + public void testSingleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick() { longPress(7); shiftTap(17); shiftTap(10); assertRangeSelection(7, 10); } - @Test - public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick_Backwards() { + public void testSingleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick_Backwards() { mManager.onLongPress(TestInputEvent.tap(17)); shiftTap(7); shiftTap(14); @@ -179,16 +167,14 @@ public class MultiSelectManagerTest { } - @Test - public void singleTapUp_ShiftReversesSelectionDirection() { + public void testSingleTapUp_ShiftReversesSelectionDirection() { longPress(7); shiftTap(17); shiftTap(0); assertRangeSelection(0, 7); } - @Test - public void singleSelectMode() { + public void testSingleSelectMode() { mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE); mManager.addCallback(mCallback); longPress(20); @@ -196,8 +182,7 @@ public class MultiSelectManagerTest { assertSelection(13); } - @Test - public void singleSelectMode_ShiftTap() { + public void testSingleSelectMode_ShiftTap() { mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE); mManager.addCallback(mCallback); longPress(13); @@ -205,8 +190,7 @@ public class MultiSelectManagerTest { assertSelection(20); } - @Test - public void provisionaSelection() { + public void testProvisionalSelection() { Selection s = mManager.getSelection(); assertSelection(); @@ -298,6 +282,7 @@ public class MultiSelectManagerTest { Set<Integer> ignored = new HashSet<>(); private int mLastChangedPosition; private boolean mLastChangedSelected; + private boolean mSelectionChanged = false; @Override public void onItemStateChanged(int position, boolean selected) { @@ -311,7 +296,13 @@ public class MultiSelectManagerTest { } @Override - public void onSelectionChanged() {} + public void onSelectionChanged() { + mSelectionChanged = true; + } + + void assertSelectionChanged() { + assertTrue(mSelectionChanged); + } } private static final class TestHolder extends RecyclerView.ViewHolder { diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java index 87d7e15a4072..aa50b48e6c16 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java @@ -22,14 +22,12 @@ import static org.junit.Assert.assertTrue; import android.graphics.Point; import android.graphics.Rect; import android.support.v7.widget.RecyclerView.OnScrollListener; +import android.test.AndroidTestCase; import android.util.SparseBooleanArray; import com.android.documentsui.MultiSelectManager.GridModel; -import org.junit.After; -import org.junit.Test; - -public class MultiSelectManager_GridModelTest { +public class MultiSelectManager_GridModelTest extends AndroidTestCase { private static final int VIEW_PADDING_PX = 5; private static final int CHILD_VIEW_EDGE_PX = 100; @@ -53,14 +51,13 @@ public class MultiSelectManager_GridModelTest { }); } - @After + @Override public void tearDown() { model = null; helper = null; lastSelection = null; } - @Test public void testSelectionLeftOfItems() { setUp(20, 5); model.startSelection(new Point(0, 10)); @@ -69,7 +66,6 @@ public class MultiSelectManager_GridModelTest { assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin()); } - @Test public void testSelectionRightOfItems() { setUp(20, 4); model.startSelection(new Point(viewWidth - 1, 10)); @@ -78,7 +74,6 @@ public class MultiSelectManager_GridModelTest { assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin()); } - @Test public void testSelectionAboveItems() { setUp(20, 4); model.startSelection(new Point(10, 0)); @@ -87,7 +82,6 @@ public class MultiSelectManager_GridModelTest { assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin()); } - @Test public void testSelectionBelowItems() { setUp(5, 4); model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1)); @@ -96,7 +90,6 @@ public class MultiSelectManager_GridModelTest { assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin()); } - @Test public void testVerticalSelectionBetweenItems() { setUp(20, 4); model.startSelection(new Point(106, 0)); @@ -105,7 +98,6 @@ public class MultiSelectManager_GridModelTest { assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin()); } - @Test public void testHorizontalSelectionBetweenItems() { setUp(20, 4); model.startSelection(new Point(0, 105)); @@ -114,7 +106,6 @@ public class MultiSelectManager_GridModelTest { assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin()); } - @Test public void testGrowingAndShrinkingSelection() { setUp(20, 4); model.startSelection(new Point(0, 0)); @@ -145,7 +136,6 @@ public class MultiSelectManager_GridModelTest { assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin()); } - @Test public void testSelectionMovingAroundOrigin() { setUp(16, 4); model.startSelection(new Point(210, 210)); @@ -160,7 +150,6 @@ public class MultiSelectManager_GridModelTest { assertEquals(10, model.getPositionNearestOrigin()); } - @Test public void testScrollingBandSelect() { setUp(40, 4); model.startSelection(new Point(0, 0)); diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java index 51b542b2ae8c..eddf4ef6fede 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java @@ -18,16 +18,16 @@ package com.android.documentsui; import static org.junit.Assert.*; +import android.test.AndroidTestCase; + import com.android.documentsui.MultiSelectManager.Selection; -import org.junit.Before; -import org.junit.Test; -public class MultiSelectManager_SelectionTest { +public class MultiSelectManager_SelectionTest extends AndroidTestCase{ private Selection selection; - @Before + @Override public void setUp() throws Exception { selection = new Selection(); selection.add(3); @@ -35,8 +35,7 @@ public class MultiSelectManager_SelectionTest { selection.add(9); } - @Test - public void add() { + public void testAdd() { // We added in setUp. assertEquals(3, selection.size()); assertContains(3); @@ -44,29 +43,25 @@ public class MultiSelectManager_SelectionTest { assertContains(9); } - @Test - public void remove() { + public void testRemove() { selection.remove(3); selection.remove(5); assertEquals(1, selection.size()); assertContains(9); } - @Test - public void clear() { + public void testClear() { selection.clear(); assertEquals(0, selection.size()); } - @Test - public void isEmpty() { + public void testIsEmpty() { assertTrue(new Selection().isEmpty()); selection.clear(); assertTrue(selection.isEmpty()); } - @Test - public void sizeAndGet() { + public void testSizeAndGet() { Selection other = new Selection(); for (int i = 0; i < selection.size(); i++) { other.add(selection.get(i)); @@ -74,13 +69,11 @@ public class MultiSelectManager_SelectionTest { assertEquals(selection.size(), other.size()); } - @Test - public void equalsSelf() { + public void testEqualsSelf() { assertEquals(selection, selection); } - @Test - public void equalsOther() { + public void testEqualsOther() { Selection other = new Selection(); other.add(3); other.add(5); @@ -89,23 +82,20 @@ public class MultiSelectManager_SelectionTest { assertEquals(selection.hashCode(), other.hashCode()); } - @Test - public void equalsCopy() { + public void testEqualsCopy() { Selection other = new Selection(); other.copyFrom(selection); assertEquals(selection, other); assertEquals(selection.hashCode(), other.hashCode()); } - @Test - public void notEquals() { + public void testNotEquals() { Selection other = new Selection(); other.add(789); assertFalse(selection.equals(other)); } - @Test - public void expandBefore() { + public void testExpandBefore() { selection.expand(2, 10); assertEquals(3, selection.size()); assertContains(13); @@ -113,8 +103,7 @@ public class MultiSelectManager_SelectionTest { assertContains(19); } - @Test - public void expandAfter() { + public void testExpandAfter() { selection.expand(10, 10); assertEquals(3, selection.size()); assertContains(3); @@ -122,8 +111,7 @@ public class MultiSelectManager_SelectionTest { assertContains(9); } - @Test - public void expandSplit() { + public void testExpandSplit() { selection.expand(5, 10); assertEquals(3, selection.size()); assertContains(3); @@ -131,8 +119,7 @@ public class MultiSelectManager_SelectionTest { assertContains(19); } - @Test - public void expandEncompased() { + public void testExpandEncompased() { selection.expand(2, 10); assertEquals(3, selection.size()); assertContains(13); @@ -140,8 +127,7 @@ public class MultiSelectManager_SelectionTest { assertContains(19); } - @Test - public void collapseBefore() { + public void testCollapseBefore() { selection.collapse(0, 2); assertEquals(3, selection.size()); assertContains(1); @@ -149,8 +135,7 @@ public class MultiSelectManager_SelectionTest { assertContains(7); } - @Test - public void collapseAfter() { + public void testCollapseAfter() { selection.collapse(10, 10); assertEquals(3, selection.size()); assertContains(3); @@ -158,8 +143,7 @@ public class MultiSelectManager_SelectionTest { assertContains(9); } - @Test - public void collapseAcross() { + public void testCollapseAcross() { selection.collapse(0, 10); assertEquals(0, selection.size()); } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java index 132570674b48..7d3498e4e079 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java @@ -19,7 +19,6 @@ package com.android.documentsui; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; -import com.android.documentsui.BaseActivity.State; import com.android.documentsui.model.RootInfo; import com.google.common.collect.Lists; diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java deleted file mode 100644 index be3f2515057e..000000000000 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.documentsui; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; - -@RunWith(Suite.class) -@SuiteClasses({ - MultiSelectManager_GridModelTest.class, - MultiSelectManager_SelectionTest.class, - MultiSelectManagerTest.class -}) - -/** - * This test suite can be run using the "art" runtime (which can be built - * via the `build-art-host` target.) You'll also need to "mma -j32" the - * DocumentsUI package to ensure all deps are built. - * - * <p>Once the dependencies have been built, the tests can be executed as follows: - * - * <pre> - * CP=$OUT/system/framework/framework.jar:\ - * $OUT/system/framework/core-junit.jar:\ - * $OUT/system/app/DocumentsUI/DocumentsUI.apk:\ - * $OUT/data/app/DocumentsUITests/DocumentsUITests.apk - * - * art -cp $CP org.junit.runner.JUnitCore com.android.documentsui.UnitTests - * </pre> - */ -public class UnitTests {} diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 393771a9b447..18335b6586a8 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -38,6 +38,7 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; +import android.provider.MediaStore; import android.text.TextUtils; import android.util.ArrayMap; import android.util.DebugUtils; @@ -380,12 +381,31 @@ public class ExternalStorageProvider extends DocumentsProvider { @Override public void deleteDocument(String docId) throws FileNotFoundException { final File file = getFileForDocId(docId); - if (file.isDirectory()) { + final boolean isDirectory = file.isDirectory(); + if (isDirectory) { FileUtils.deleteContents(file); } if (!file.delete()) { throw new IllegalStateException("Failed to delete " + file); } + + final ContentResolver resolver = getContext().getContentResolver(); + final Uri externalUri = MediaStore.Files.getContentUri("external"); + + // Remove media store entries for any files inside this directory, using + // path prefix match. Logic borrowed from MtpDatabase. + if (isDirectory) { + final String path = file.getAbsolutePath() + "/"; + resolver.delete(externalUri, + "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)", + new String[] { path + "%", Integer.toString(path.length()), path }); + } + + // Remove media store entry for this exact file. + final String path = file.getAbsolutePath(); + resolver.delete(externalUri, + "_data LIKE ?1 AND lower(_data)=lower(?2)", + new String[] { path, path }); } @Override diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java index aeac91215be6..2033159af720 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java @@ -23,6 +23,7 @@ import com.android.internal.telephony.PhoneConstants; import android.content.Context; import android.content.res.ColorStateList; +import android.content.res.Configuration; import android.content.res.Resources; import android.app.AlertDialog; import android.app.AlertDialog.Builder; @@ -96,6 +97,12 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView { } @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + resetState(); + } + + @Override protected int getPromtReasonStringRes(int reason) { // No message on SIM Pin return 0; diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index e34286572cb6..57ee319f8ff3 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -121,7 +121,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private static final int MSG_DEVICE_PROVISIONED = 308; private static final int MSG_DPM_STATE_CHANGED = 309; private static final int MSG_USER_SWITCHING = 310; - private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 311; private static final int MSG_KEYGUARD_RESET = 312; private static final int MSG_BOOT_COMPLETED = 313; private static final int MSG_USER_SWITCH_COMPLETE = 314; @@ -233,9 +232,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { case MSG_USER_SWITCH_COMPLETE: handleUserSwitchComplete(msg.arg1); break; - case MSG_KEYGUARD_VISIBILITY_CHANGED: - handleKeyguardVisibilityChanged(msg.arg1); - break; case MSG_KEYGUARD_RESET: handleKeyguardReset(); break; @@ -1344,19 +1340,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } /** - * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED} + * Notifies that the visibility state of Keyguard has changed. + * + * <p>Needs to be called from the main thread. */ - private void handleKeyguardVisibilityChanged(int showing) { - if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")"); - boolean isShowing = (showing == 1); - mKeyguardIsVisible = isShowing; + public void onKeyguardVisibilityChanged(boolean showing) { + if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")"); + mKeyguardIsVisible = showing; for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { - cb.onKeyguardVisibilityChangedRaw(isShowing); + cb.onKeyguardVisibilityChangedRaw(showing); } } - if (!isShowing) { + if (!showing) { mFingerprintAlreadyAuthenticated = false; } updateFingerprintListeningState(); @@ -1477,13 +1474,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } - public void sendKeyguardVisibilityChanged(boolean showing) { - if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")"); - Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED); - message.arg1 = showing ? 1 : 0; - message.sendToTarget(); - } - public void sendKeyguardReset() { mHandler.obtainMessage(MSG_KEYGUARD_RESET).sendToTarget(); } diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java index 7cc7413bab3d..af7f691bdd64 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java @@ -22,12 +22,14 @@ import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbManager; import android.mtp.MtpConstants; import android.mtp.MtpDevice; +import android.mtp.MtpEvent; import android.mtp.MtpObjectInfo; +import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; -import android.provider.DocumentsContract.Document; -import android.provider.DocumentsContract; import android.util.SparseArray; +import com.android.internal.annotations.VisibleForTesting; + import java.io.FileNotFoundException; import java.io.IOException; @@ -188,7 +190,13 @@ class MtpManager { } } - private MtpDevice getDevice(int deviceId) throws IOException { + @VisibleForTesting + MtpEvent readEvent(int deviceId, CancellationSignal signal) throws IOException { + final MtpDevice device = getDevice(deviceId); + return device.readEvent(signal); + } + + private synchronized MtpDevice getDevice(int deviceId) throws IOException { final MtpDevice device = mDevices.get(deviceId); if (device == null) { throw new IOException("USB device " + deviceId + " is not opened."); diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java index 2c1f115ec92b..554777160792 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java @@ -16,35 +16,101 @@ package com.android.mtp; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbManager; +import android.os.CancellationSignal; +import android.os.OperationCanceledException; import android.test.InstrumentationTestCase; +import java.io.IOException; import java.util.HashMap; +import java.util.concurrent.CountDownLatch; +@RealDeviceTest public class MtpManagerTest extends InstrumentationTestCase { - @RealDeviceTest - public void testBasic() throws Exception { - final UsbDevice usbDevice = findDevice(); - final MtpManager manager = new MtpManager(getContext()); - manager.openDevice(usbDevice.getDeviceId()); - waitForStorages(manager, usbDevice.getDeviceId()); - manager.closeDevice(usbDevice.getDeviceId()); + private static final String ACTION_USB_PERMISSION = + "com.android.mtp.USB_PERMISSION"; + private static final int TIMEOUT_MS = 1000; + UsbManager mUsbManager; + MtpManager mManager; + UsbDevice mUsbDevice; + int mRequest; + + @Override + public void setUp() throws Exception { + mUsbManager = getContext().getSystemService(UsbManager.class); + mUsbDevice = findDevice(); + mManager = new MtpManager(getContext()); + mManager.openDevice(mUsbDevice.getDeviceId()); + waitForStorages(mManager, mUsbDevice.getDeviceId()); + } + + @Override + public void tearDown() throws IOException { + mManager.closeDevice(mUsbDevice.getDeviceId()); + } + + public void testCancelEvent() throws Exception { + final CancellationSignal signal = new CancellationSignal(); + final Thread thread = new Thread() { + @Override + public void run() { + try { + mManager.readEvent(mUsbDevice.getDeviceId(), signal); + } catch (OperationCanceledException | IOException e) { + show(e.getMessage()); + } + } + }; + thread.start(); + Thread.sleep(TIMEOUT_MS); + signal.cancel(); + thread.join(TIMEOUT_MS); + } + + private void requestPermission(UsbDevice device) throws InterruptedException { + if (mUsbManager.hasPermission(device)) { + return; + } + final CountDownLatch latch = new CountDownLatch(1); + final BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + latch.countDown(); + getInstrumentation().getTargetContext().unregisterReceiver(this); + } + }; + getInstrumentation().getTargetContext().registerReceiver( + receiver, new IntentFilter(ACTION_USB_PERMISSION)); + mUsbManager.requestPermission(device, PendingIntent.getBroadcast( + getInstrumentation().getTargetContext(), + 0 /* requstCode */, + new Intent(ACTION_USB_PERMISSION), + 0 /* flags */)); + latch.await(); + assertTrue(mUsbManager.hasPermission(device)); } private UsbDevice findDevice() throws InterruptedException { - final UsbManager usbManager = getContext().getSystemService(UsbManager.class); while (true) { - final HashMap<String,UsbDevice> devices = usbManager.getDeviceList(); + final HashMap<String,UsbDevice> devices = mUsbManager.getDeviceList(); if (devices.size() == 0) { show("Wait for devices."); Thread.sleep(1000); continue; } final UsbDevice device = devices.values().iterator().next(); - final UsbDeviceConnection connection = usbManager.openDevice(device); + requestPermission(device); + final UsbDeviceConnection connection = mUsbManager.openDevice(device); + if (connection == null) { + fail("Cannot open USB connection."); + } for (int i = 0; i < device.getInterfaceCount(); i++) { // Since the test runs real environment, we need to call claim interface with // force = true to rob interfaces from other applications. diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java index 9641ad764fae..22daaf2971e6 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java @@ -17,7 +17,10 @@ package com.android.mtp; import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) @interface RealDeviceTest {} diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java index 9824d28e1fe4..a24337534e5b 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java @@ -45,8 +45,11 @@ public class TestResultInstrumentation extends InstrumentationTestRunner impleme } private void show(String tag, Test test, Throwable t) { + String message = ""; + if (t != null && t.getMessage() != null) { + message = t.getMessage(); + } TestResultActivity.show( - getContext(), - String.format("[%s] %s %s", tag, test.toString(), t != null ? t.getMessage() : "")); + getContext(), String.format("[%s] %s %s", tag, test.toString(), message)); } } diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp index b5d91385abe5..1530a02c22fe 100644 --- a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp +++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp @@ -166,7 +166,7 @@ static void writeBitmapPixels(JNIEnv* env, jclass /* clazz */, jobject jbitmap, } } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { {"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels}, {"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels}, }; diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml index 8e41a349fde3..f88eca56d32a 100644 --- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml +++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml @@ -46,7 +46,7 @@ <string name="savetopdf_button" msgid="2976186791686924743">"PDF sifatida saqlash"</string> <string name="print_options_expanded" msgid="6944679157471691859">"Chop qilish tanlamalari yoyildi"</string> <string name="print_options_collapsed" msgid="7455930445670414332">"Chop qilish tanlamalari yig‘ildi"</string> - <string name="search" msgid="5421724265322228497">"Izlash"</string> + <string name="search" msgid="5421724265322228497">"Qidirish"</string> <string name="all_printers_label" msgid="3178848870161526399">"Barcha printerlar"</string> <string name="add_print_service_label" msgid="5356702546188981940">"Xizmat qo‘shish"</string> <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Izlash oynasi ko‘rsatildi"</string> diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 1cd2908e77e9..c324abd0dd22 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -204,9 +204,6 @@ <!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED --> <bool name="def_wake_gesture_enabled">true</bool> - <!-- Default for Settings.Global.GUEST_USER_ENABLED --> - <bool name="def_guest_user_enabled">true</bool> - <!-- Default state of tap to wake --> <bool name="def_double_tap_to_wake">true</bool> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index ee296d90608f..d4e428e280b6 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -1693,20 +1693,7 @@ class DatabaseHelper extends SQLiteOpenHelper { } if (upgradeVersion < 105) { - if (mUserHandle == UserHandle.USER_SYSTEM) { - db.beginTransaction(); - SQLiteStatement stmt = null; - try { - stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)" - + " VALUES(?,?);"); - loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED, - R.bool.def_guest_user_enabled); - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - if (stmt != null) stmt.close(); - } - } + // No-op: GUEST_USER_ENABLED setting was removed upgradeVersion = 105; } @@ -2705,8 +2692,6 @@ class DatabaseHelper extends SQLiteOpenHelper { loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName()); - loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED, - R.bool.def_guest_user_enabled); loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 93dc88950fe5..8fc7ad089427 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -206,7 +206,7 @@ android:resumeWhilePausing="true" android:screenOrientation="behind" android:resizeableActivity="true" - android:theme="@style/config_recents_activity_theme"> + android:theme="@style/RecentsTheme.Wallpaper"> <intent-filter> <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" /> </intent-filter> diff --git a/packages/SystemUI/res/drawable/ic_qs_lock.xml b/packages/SystemUI/res/drawable/ic_qs_lock.xml new file mode 100644 index 000000000000..204af7e81f4c --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_lock.xml @@ -0,0 +1,25 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + + <path + android:fillColor="@color/keyguard_affordance" + android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_qs_lock_open.xml b/packages/SystemUI/res/drawable/ic_qs_lock_open.xml new file mode 100644 index 000000000000..c877f063b7a8 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_lock_open.xml @@ -0,0 +1,25 @@ +<!-- +Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + + <path + android:fillColor="@color/keyguard_affordance" + android:pathData="M12.0,17.0c1.1,0.0 2.0,-0.9 2.0,-2.0s-0.9,-2.0 -2.0,-2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0S10.9,17.0 12.0,17.0zM18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l1.9,0.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM18.0,20.0L6.0,20.0L6.0,10.0l12.0,0.0L18.0,20.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml new file mode 100644 index 000000000000..f11b690b90af --- /dev/null +++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml @@ -0,0 +1,24 @@ +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF0000FF" + android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,10.0l16.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml new file mode 100644 index 000000000000..79ade42cc94e --- /dev/null +++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml @@ -0,0 +1,24 @@ +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF0000FF" + android:pathData="M24.0,0.0L0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0zM14.0,4.0l0.0,16.0L4.0,20.0L4.0,4.0L14.0,4.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml new file mode 100644 index 000000000000..49c2a38ce48e --- /dev/null +++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml @@ -0,0 +1,24 @@ +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF0000FF" + android:pathData="M0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0L0.0,24.0zM10.0,20.0L10.0,4.0l10.0,0.0l0.0,16.0L10.0,20.0z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml new file mode 100644 index 000000000000..c3abec222e7d --- /dev/null +++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml @@ -0,0 +1,24 @@ +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF0000FF" + android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM20.0,14.0L4.0,14.0L4.0,4.0l16.0,0.0L20.0,14.0z"/> +</vector> diff --git a/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml index a718d4d57a56..0a4c0868fbd6 100644 --- a/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml +++ b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml @@ -27,6 +27,20 @@ android:layout_height="wrap_content" android:orientation="horizontal"> <Button + android:id="@+id/place_dock_left" + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_weight="1" + android:layout_margin="10dp" + android:background="@drawable/vector_drawable_place_dock_left" /> + <Button + android:id="@+id/place_dock_right" + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_weight="1" + android:layout_margin="10dp" + android:background="@drawable/vector_drawable_place_dock_right" /> + <Button android:id="@+id/place_left" android:layout_width="36dp" android:layout_height="36dp" diff --git a/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml index 250f53da1cea..bf5207a7e43c 100644 --- a/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml +++ b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml @@ -27,6 +27,20 @@ android:layout_height="wrap_content" android:orientation="horizontal"> <Button + android:id="@+id/place_dock_top" + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_weight="1" + android:layout_margin="10dp" + android:background="@drawable/vector_drawable_place_dock_top" /> + <Button + android:id="@+id/place_dock_bottom" + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_weight="1" + android:layout_margin="10dp" + android:background="@drawable/vector_drawable_place_dock_bottom" /> + <Button android:id="@+id/place_top" android:layout_width="36dp" android:layout_height="36dp" diff --git a/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml index 26c9b1af5bc1..6e92afc6d0bf 100644 --- a/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml +++ b/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml @@ -27,6 +27,20 @@ android:layout_height="wrap_content" android:orientation="horizontal"> <Button + android:id="@+id/place_dock_left" + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_weight="1" + android:layout_margin="10dp" + android:background="@drawable/vector_drawable_place_dock_left" /> + <Button + android:id="@+id/place_dock_right" + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_weight="1" + android:layout_margin="10dp" + android:background="@drawable/vector_drawable_place_dock_right" /> + <Button android:id="@+id/place_left" android:layout_width="36dp" android:layout_height="36dp" diff --git a/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml index e180daa7f415..faa5f4be8d68 100644 --- a/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml +++ b/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml @@ -27,6 +27,20 @@ android:layout_height="wrap_content" android:orientation="horizontal"> <Button + android:id="@+id/place_dock_top" + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_weight="1" + android:layout_margin="10dp" + android:background="@drawable/vector_drawable_place_dock_top" /> + <Button + android:id="@+id/place_dock_bottom" + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_weight="1" + android:layout_margin="10dp" + android:background="@drawable/vector_drawable_place_dock_bottom" /> + <Button android:id="@+id/place_top" android:layout_width="36dp" android:layout_height="36dp" diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml index 8140dd68710e..064d2258150f 100644 --- a/packages/SystemUI/res/layout/recents.xml +++ b/packages/SystemUI/res/layout/recents.xml @@ -39,12 +39,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - <!-- Debug Overlay View --> - <ViewStub android:id="@+id/debug_overlay_stub" - android:layout="@layout/recents_debug_overlay" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - <!-- Nav Bar Scrim View --> <ImageView android:id="@+id/nav_bar_scrim" diff --git a/packages/SystemUI/res/layout/recents_debug_overlay.xml b/packages/SystemUI/res/layout/recents_debug_overlay.xml deleted file mode 100644 index d23495e6043e..000000000000 --- a/packages/SystemUI/res/layout/recents_debug_overlay.xml +++ /dev/null @@ -1,35 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<com.android.systemui.recents.views.DebugOverlayView - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:focusable="false"> - <SeekBar - android:id="@+id/debug_seek_bar_1" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top" - android:layout_marginTop="25dp" /> - <SeekBar - android:id="@+id/debug_seek_bar_2" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top" - android:layout_marginTop="50dp" /> -</com.android.systemui.recents.views.DebugOverlayView> - - diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 1473f24bae42..c7c7f1a7e53b 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Net\nprioriteit"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Net\nwekkers"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laai tans vinnig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laai tans stadig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Wissel gebruiker"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Wissel gebruiker, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 7ab6af9cb72d..f49f5bc60c11 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ቅድሚያ ተሰጪ\nብቻ"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ማንቂያዎች\nብቻ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ኃይል በፍጥነት በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ኃይል በዝግታ በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ተጠቃሚ ቀይር"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ተጠቃሚ ይለውጡ፣ የአሁን ተጠቃሚ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"የአሁን ተጠቃሚ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index bd026501dc45..aaf20cce429a 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -329,6 +329,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"الأولوية \nفقط"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"التنبيهات\nفقط"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"جارٍ الشحن سريعًا (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"جارٍ الشحن ببطء (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"تبديل المستخدم"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"تبديل المستخدم، المستخدم الحالي <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"المستخدم الحالي <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml index a0d7d2b21c7c..0efc82b03b2b 100644 --- a/packages/SystemUI/res/values-az-rAZ/strings.xml +++ b/packages/SystemUI/res/values-az-rAZ/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnız\nprioritet"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnız\nalarmlar"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sürətli qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ləng qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"İstifadəçiləri dəyişin, indiki istifadəçi: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Cari istifadəçi <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index a14d0fc70c07..680577947a35 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nс приоритет"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nбудилници"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Зарежда се бързо (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Зарежда се бавно (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Превключване между потребителите"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Превключване на потребителя – текущият е <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Текущ потребител – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml index e819d54e0901..c0ffe2c720e6 100644 --- a/packages/SystemUI/res/values-bn-rBD/strings.xml +++ b/packages/SystemUI/res/values-bn-rBD/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"শুধুমাত্র\nঅগ্রাধিকার"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"শুধুমাত্র\nঅ্যালার্মগুলি"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"দ্রুত চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ধীরে ধীরে চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ব্যবহারকারী পাল্টে দিন"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ব্যবহারকারী পাল্টান, বর্তমান ব্যবহারকারী <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"<xliff:g id="CURRENT_USER_NAME">%s</xliff:g> হল বর্তমান ব্যবহারকারী"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index cc37162f99c1..c955f34ad8c3 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Només\ninterr. prior."</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Només\nalarmes"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Càrrega ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Càrrega lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Canvia d\'usuari"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Canvia l\'usuari. Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> @@ -406,7 +408,7 @@ <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> és el diàleg de volum"</string> <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca per restaurar l\'original."</string> <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estàs utilitzant el perfil professional"</string> - <string name="system_ui_tuner" msgid="708224127392452018">"Configurador de la IU del sistema"</string> + <string name="system_ui_tuner" msgid="708224127392452018">"Personalitzador d\'interfície d\'usuari"</string> <string name="show_battery_percentage" msgid="5444136600512968798">"Mostra el percentatge de la bateria inserit"</string> <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostra el percentatge del nivell de bateria dins de la icona de la barra d\'estat quan no s\'estigui carregant"</string> <string name="quick_settings" msgid="10042998191725428">"Configuració ràpida"</string> @@ -428,12 +430,12 @@ <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Zona Wi-Fi"</string> <string name="accessibility_managed_profile" msgid="6613641363112584120">"Perfil professional"</string> <string name="tuner_warning_title" msgid="7094689930793031682">"Diversió per a uns quants, però no per a tothom"</string> - <string name="tuner_warning" msgid="8730648121973575701">"El Configurador de la IU del sistema presenta opcions addicionals per canviar i personalitzar la interfície d\'usuari d\'Android. És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string> + <string name="tuner_warning" msgid="8730648121973575701">"El Personalitzador d\'interfície d\'usuari presenta opcions addicionals per canviar i personalitzar la interfície d\'usuari d\'Android. És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string> <string name="tuner_persistent_warning" msgid="8597333795565621795">"És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string> <string name="got_it" msgid="2239653834387972602">"D\'acord"</string> - <string name="tuner_toast" msgid="603429811084428439">"Enhorabona! El Configurador de la IU del sistema s\'ha afegit a Configuració."</string> + <string name="tuner_toast" msgid="603429811084428439">"Enhorabona! El Personalitzador d\'interfície d\'usuari s\'ha afegit a Configuració."</string> <string name="remove_from_settings" msgid="8389591916603406378">"Treu de Configuració"</string> - <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vols treure el Configurador de la UI del sistema de Configuració i deixar d\'utilitzar-ne totes les funcions?"</string> + <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vols suprimir el Personalitzador d\'interfície d\'usuari de Configuració i deixar d\'utilitzar-ne totes les funcions?"</string> <string name="activity_not_found" msgid="348423244327799974">"L\'aplicació no està instal·lada al dispositiu"</string> <string name="clock_seconds" msgid="7689554147579179507">"Mostra els segons del rellotge"</string> <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index a73947fdfb05..18fd994f232e 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -329,6 +329,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Pouze\nprioritní"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Pouze\nbudíky"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Rychlé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Pomalé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Přepnout uživatele"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Přepnout uživatele, aktuální uživatel: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuální uživatel <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 6f491874e6a8..5a2dd3300b23 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -183,12 +183,12 @@ <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Flytilstand er slået til."</string> <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Flytilstand er slået fra."</string> <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Flytilstand er slået til."</string> - <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Vil ikke forstyrres\" er slået til, kun prioritet."</string> - <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"\"Vil ikke forstyrres\" er slået til, total stilhed."</string> - <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Vil ikke forstyrres\" er slået til, kun alarmer."</string> - <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Vil ikke forstyrres\" er slået fra."</string> - <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Vil ikke forstyrres\" er slået fra."</string> - <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Vil ikke forstyrres\" er slået til."</string> + <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Forstyr ikke\" er slået til, kun prioritet."</string> + <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"\"Forstyr ikke\" er slået til, total stilhed."</string> + <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Forstyr ikke\" er slået til, kun alarmer."</string> + <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Forstyr ikke\" er slået fra."</string> + <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Forstyr ikke\" er slået fra."</string> + <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Forstyr ikke\" er slået til."</string> <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth er slået fra."</string> <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth er slået til."</string> <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Opretter forbindelse til Bluetooth."</string> @@ -236,7 +236,7 @@ <string name="dessert_case" msgid="1295161776223959221">"Dessertcase"</string> <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string> <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> - <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Vil ikke forstyrres"</string> + <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Forstyr ikke"</string> <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Kun prioritet"</string> <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Kun Alarmer"</string> <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Total stilhed"</string> @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kun\nprioritet"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kun\nalarmer"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Oplader (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hurtig opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langsom opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Skift bruger"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Skift bruger. Nuværende bruger er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Nuværende bruger: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index a659077bd821..a8143a461090 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Nur\nwichtige"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Nur\nWecker"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Wird schnell aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wird langsam aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Nutzer wechseln"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Nutzer wechseln. Aktueller Nutzer: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktueller Nutzer <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index bcfc4589a6b8..6031d3bb4fff 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Μόνο\nπροτεραιότητας"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Μόνο\nειδοποιήσεις"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Γρήγορη φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Αργή φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Εναλλαγή χρήστη"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Εναλλαγή χρήστη, τρέχων χρήστης <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Τρέχων χρήστης <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index fb781d4d91ea..bef7661a52ef 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index fb781d4d91ea..bef7661a52ef 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index fb781d4d91ea..bef7661a52ef 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en/donottranslate.xml b/packages/SystemUI/res/values-en/donottranslate.xml new file mode 100644 index 000000000000..9f04e1f50b14 --- /dev/null +++ b/packages/SystemUI/res/values-en/donottranslate.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> + <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available --> + <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time_fast</item> + <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available --> + <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time_slowly</item> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 10834a23baa7..15902653a7f2 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\nprioridad"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carga rápida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carga lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar usuario"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar de usuario (usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"El usuario actual es <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 37c81f4936c0..082e7624cbd0 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\ncon prioridad"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar de usuario"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar de usuario (usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml index f4218a3a6eb3..4add1471be93 100644 --- a/packages/SystemUI/res/values-et-rEE/strings.xml +++ b/packages/SystemUI/res/values-et-rEE/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Ainult\nprioriteetsed"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ainult\nalarmid"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Kiirlaadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Aeglane laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Kasutaja vahetamine"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Kasutaja vahetamine, praegune kasutaja: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Praegune kasutaja <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml index 0e5532cd9db7..4f5c9f26799e 100644 --- a/packages/SystemUI/res/values-eu-rES/strings.xml +++ b/packages/SystemUI/res/values-eu-rES/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Lehentasunezkoak\nsoilik"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmak\nsoilik"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Bizkor kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mantso kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Aldatu erabiltzailea"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Aldatu erabiltzailez. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita duena."</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Uneko erabiltzailea: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 7593f46e6c70..6fa7e1c19efd 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -275,7 +275,7 @@ <string name="quick_settings_inversion_label" msgid="8790919884718619648">"برگردان رنگها"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"حالت تصحیح رنگ"</string> <string name="quick_settings_more_settings" msgid="326112621462813682">"تنظیمات بیشتر"</string> - <string name="quick_settings_done" msgid="3402999958839153376">"انجام شد"</string> + <string name="quick_settings_done" msgid="3402999958839153376">"تمام"</string> <string name="quick_settings_connected" msgid="1722253542984847487">"متصل"</string> <string name="quick_settings_connecting" msgid="47623027419264404">"در حال اتصال..."</string> <string name="quick_settings_tethering_label" msgid="7153452060448575549">"اتصال به اینترنت با تلفن همراه"</string> @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"فقط\nاولویتدار"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"فقط\nهشدارها"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"در حال شارژ سریع (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"در حال شارژ آهسته (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"تغییر کاربر"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"تعویض کاربر، کاربر کنونی <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"کاربر کنونی <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 6c4a0299069b..655cf312b5dd 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vain\ntärkeät"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vain\nherätykset"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nopea lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Hidas lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Vaihda käyttäjää"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Vaihda käyttäjä (nyt <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Nykyinen käyttäjä: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 07a2fc349f5e..2f2c3319ac17 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorités\nuniquement"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 0aa45ae8a393..9f3443197a52 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml index ec64f229ea4e..df90ef4dd550 100644 --- a/packages/SystemUI/res/values-gl-rES/strings.xml +++ b/packages/SystemUI/res/values-gl-rES/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Só\nprioridade"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Só\nalarmas"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para finalizar a carga)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápido (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lento (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar usuario"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar usuario, usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml index e873c95f14f7..42ee460ad880 100644 --- a/packages/SystemUI/res/values-gu-rIN/strings.xml +++ b/packages/SystemUI/res/values-gu-rIN/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ફક્ત\nપ્રાધાન્યતા"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ફક્ત\nએલાર્મ્સ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ચાર્જ થઈ રહ્યું છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ઝડપથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ધીમેથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"વપરાશકર્તા સ્વિચ કરો"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"વપરાશકર્તાને સ્વિચ કરો, વર્તમાન વપરાશકર્તા <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"વર્તમાન વપરાશકર્તા <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 83ac46eaf42d..86f536dce040 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवल\nप्राथमिकता"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवल\nअलार्म"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूरा होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> बाकी)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"तेज़ी से चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में हो जाएगा)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"धीरे चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में पूरा हो जाएगा)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"उपयोगकर्ता स्विच करें"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"उपयोगकर्ता स्विच करें, वर्तमान उपयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"वर्तमान उपयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index b5d993117334..043e7ada0ddc 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -326,6 +326,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprioritetno"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Promjena korisnika"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Promjena korisnika, trenutačni korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Trenutačan korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 79390a69990e..e2b08129eabc 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Csak\nprioritás"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Csak\nriasztások"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Gyors töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lassú töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Felhasználóváltás"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Felhasználóváltás (a jelenlegi felhasználó: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Jelenlegi felhasználó (<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml index 9f48b2618e3e..f8fc232106bb 100644 --- a/packages/SystemUI/res/values-hy-rAM/strings.xml +++ b/packages/SystemUI/res/values-hy-rAM/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Միայն\nկարևորները"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Միայն\nզարթուցիչ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Արագ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Դանդաղ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Անջատել օգտվողին"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Փոխել օգտվողին. ներկայիս օգտվողն է՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Ընթացիկ օգտվողը՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 600241151aab..7dbcda92ede1 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Hanya\nprioritas"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Hanya\nalarm"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengisi daya dengan cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengisi daya dengan lambat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Beralih pengguna"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Ganti pengguna, pengguna saat ini <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Pengguna saat ini <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml index e8e053090fda..b28b6fd80e31 100644 --- a/packages/SystemUI/res/values-is-rIS/strings.xml +++ b/packages/SystemUI/res/values-is-rIS/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Aðeins\nforgangur"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Aðeins\nvekjarar"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Í hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Í hraðri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Í hægri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Skipta um notanda"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Skipta um notanda; núverandi notandi er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Núverandi notandi er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 8ee5f078a806..54e6f560ca67 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo con\npriorità"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nsveglie"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ricarica veloce (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ricarica lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambio utente"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambia utente, utente corrente <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utente corrente <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> @@ -354,7 +356,7 @@ <string name="user_remove_user_title" msgid="4681256956076895559">"Rimuovere l\'utente?"</string> <string name="user_remove_user_message" msgid="1453218013959498039">"Tutte le app e i dati di questo utente verranno eliminati."</string> <string name="user_remove_user_remove" msgid="7479275741742178297">"Rimuovi"</string> - <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio batteria attivo"</string> + <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio energetico attivo"</string> <string name="battery_saver_notification_text" msgid="820318788126672692">"Riduce le prestazioni e i dati in background"</string> <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Disattiva risparmio energetico"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 44058a34db49..c959febd9ab9 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"התראות בעדיפות\nבלבד"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"התראות\nבלבד"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"בטעינה מהירה (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"בטעינה איטית (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"החלפת משתמש"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"החלף משתמש. המשתמש הנוכחי הוא <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"משתמש נוכחי <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index a73f4c1d9fc6..29476d80e094 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -327,10 +327,12 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"重要な\n通知のみ"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"アラーム\nのみ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フル充電まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"急速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"低速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ユーザーを切り替える"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ユーザーを切り替える、現在のユーザーは<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"現在のユーザー: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> - <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"プロフィールを表示"</string> + <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"プロファイルを表示"</string> <string name="user_add_user" msgid="5110251524486079492">"ユーザーを追加"</string> <string name="user_new_user_name" msgid="426540612051178753">"新しいユーザー"</string> <string name="guest_nickname" msgid="8059989128963789678">"ゲスト"</string> @@ -364,10 +366,10 @@ <string name="media_projection_action_text" msgid="8470872969457985954">"今すぐ開始"</string> <string name="empty_shade_text" msgid="708135716272867002">"通知はありません"</string> <string name="device_owned_footer" msgid="3802752663326030053">"端末が監視されている可能性があります"</string> - <string name="profile_owned_footer" msgid="8021888108553696069">"プロフィールが監視されている可能性があります"</string> + <string name="profile_owned_footer" msgid="8021888108553696069">"プロファイルが監視されている可能性があります"</string> <string name="vpn_footer" msgid="2388611096129106812">"ネットワークが監視されている可能性があります"</string> <string name="monitoring_title_device_owned" msgid="7121079311903859610">"端末の監視"</string> - <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"プロフィールの監視"</string> + <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"プロファイルの監視"</string> <string name="monitoring_title" msgid="169206259253048106">"ネットワーク監視"</string> <string name="disable_vpn" msgid="4435534311510272506">"VPNを無効にする"</string> <string name="disconnect_vpn" msgid="1324915059568548655">"VPNを切断"</string> diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml index f1035a8d8fc5..d83c9e9e8ede 100644 --- a/packages/SystemUI/res/values-ka-rGE/strings.xml +++ b/packages/SystemUI/res/values-ka-rGE/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"მხოლოდ\nპრიორიტეტულები"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"მხოლოდ\nგაფრთხილებები"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"იტენება სწრაფად (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"იტენება ნელა (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"მომხმარებლის გადართვა"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"მომხმარებლის გდართვა. ამჟამინდელი მომხმარებელი <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ამჟამინდელი მომხმარებელი <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml index 8b82e5fce6c9..5c066b3c9d14 100644 --- a/packages/SystemUI/res/values-kk-rKZ/strings.xml +++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Тек\nбасымдық"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Тек\nдабылдар"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Жылдам зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Баяу зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Пайдаланушыны ауыстыру"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Пайдаланушыны ауыстыру, ағымдағы пайдаланушы <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Ағымдағы пайдаланушы: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml index b8db00f9067c..4c469b05e7e4 100644 --- a/packages/SystemUI/res/values-km-rKH/strings.xml +++ b/packages/SystemUI/res/values-km-rKH/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"អាទិភាព\nប៉ុណ្ណោះ"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"សំឡេងរោទ៍\nប៉ុណ្ណោះ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុងបញ្ចូលថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ថ្មកំពុងសាកលឿន (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ថ្មកំពុងសាកយឺតៗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ប្ដូរអ្នកប្រើ"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ប្ដូរអ្នកប្រើ អ្នកប្រើបច្ចុប្បន្ន <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"អ្នកប្រើបច្ចុប្បន្ន <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml index 316c04fe12a2..4215a9193cd7 100644 --- a/packages/SystemUI/res/values-kn-rIN/strings.xml +++ b/packages/SystemUI/res/values-kn-rIN/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ಆದ್ಯತೆ\nಮಾತ್ರ"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ಅಲಾರಮ್ಗಳು\nಮಾತ್ರ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ ( ಪೂರ್ತಿ ಆಗುವವರೆಗೆ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ವೇಗವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ನಿಧಾನ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ, ಪ್ರಸ್ತುತ ಬಳಕೆದಾರ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"<xliff:g id="CURRENT_USER_NAME">%s</xliff:g> ಪ್ರಸ್ತುತ ಬಳಕೆದಾರ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index d7f1543a87d0..8ee594652bd3 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"중요 알림만\n허용"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"알람만\n"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"고속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"저속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"사용자 전환"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"사용자 전환, 현재 사용자 <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"현재 사용자: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml index 65f91a2d62a6..ce0afd42d6de 100644 --- a/packages/SystemUI/res/values-ky-rKG/strings.xml +++ b/packages/SystemUI/res/values-ky-rKG/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Артыкчылыктуу\nгана"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ойготкучтар\nгана"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Кубатталууда (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> толгонго чейин)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Тез кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Жай кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Колдонуучуну которуу"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Колдонуучуну күйгүзүү, учурдагы колдонуучу <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Учурдагы колдонуучу <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml index d608e25ebeba..f7e23449fa0a 100644 --- a/packages/SystemUI/res/values-land/config.xml +++ b/packages/SystemUI/res/values-land/config.xml @@ -20,10 +20,6 @@ <!-- These resources are around just to allow their values to be customized for different hardware and product builds. --> <resources> - <!-- Whether we're using the tablet-optimized recents interface (we use this - value at runtime for some things) --> - <integer name="status_bar_recents_bg_gradient_degrees">90</integer> - <!-- The maximum number of rows in the QuickSettings --> <integer name="quick_settings_max_rows">2</integer> diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index a9e7735ea660..6ef1adac3e02 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -19,28 +19,6 @@ <!-- thickness (width) of the navigation bar on phones that require it --> <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen> - <!-- Recent Applications parameters --> - <!-- How far the thumbnail for a recent app appears from left edge --> - <dimen name="status_bar_recents_thumbnail_left_margin">0dp</dimen> - <!-- How far the thumbnail for a recent app appears from top edge --> - <dimen name="status_bar_recents_thumbnail_top_margin">28dp</dimen> - <!-- Padding for text descriptions --> - <dimen name="status_bar_recents_text_description_padding">8dp</dimen> - <!-- Width of application label text --> - <dimen name="status_bar_recents_app_label_width">156dip</dimen> - <!-- Left margin of application label text --> - <dimen name="status_bar_recents_app_label_left_margin">12dip</dimen> - <!-- Margin between recents container and glow on the right --> - <dimen name="status_bar_recents_right_glow_margin">0dip</dimen> - <!-- Padding between recents items --> - <dimen name="status_bar_recents_item_padding">2dip</dimen> - <!-- Where to place the app icon over the thumbnail --> - <dimen name="status_bar_recents_app_icon_left_margin">8dp</dimen> - <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen> - - <!-- The side padding for the task stack as a percentage of the width. --> - <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.26</item> - <!-- Standard notification width + gravity --> <dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen> <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer> diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml index 50b4522caabf..b45395efd6ef 100644 --- a/packages/SystemUI/res/values-lo-rLA/strings.xml +++ b/packages/SystemUI/res/values-lo-rLA/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ບຸລິມະສິດ\nເທົ່ານັ້ນ"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ໂມງປຸກ\nເທົ່ານັ້ນ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳລັງສາກໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າຈະເຕັມ)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ກຳລັງສາກໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າຈະເຕັມ)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ກຳລັງສາກໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າຈະເຕັມ)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ສະລັບຜູ່ໃຊ້"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ປ່ຽນຜູ່ໃຊ້, ຜູ່ໃຊ້ປະຈຸບັນ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ຜູ້ໃຊ້ປະຈຸບັນ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 90827785d109..194668b8b922 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tik\nprioritetiniai"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tik\nsignalai"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Greitai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lėtai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Perjungti naudotoją"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Perjungti naudotoją, dabartinis naudotojas <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Dabartinis naudotojas <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 5fb4bb0c2f86..2b3be5838d23 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -326,6 +326,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tikai\nprioritārie"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tikai\nsignāli"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ātra uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lēna uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Mainīt lietotāju"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Pārslēgt lietotāju; pašreizējais lietotājs: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Pašreizējais lietotājs: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml index 8571b3f441f1..912c30f1c225 100644 --- a/packages/SystemUI/res/values-mk-rMK/strings.xml +++ b/packages/SystemUI/res/values-mk-rMK/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприоритетни"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Се полни (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Бавно полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Промени го корисникот"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Промени го корисникот, тековен корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Тековен корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml index 4b11962a91c4..c85ecc7b8441 100644 --- a/packages/SystemUI/res/values-ml-rIN/strings.xml +++ b/packages/SystemUI/res/values-ml-rIN/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"മുൻഗണന\nമാത്രം"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"അലാറങ്ങൾ\nമാത്രം"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ചാർജ്ജുചെയ്യുന്നു (പൂർണ്ണമാകുന്നതിന്, <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"വേഗത്തിൽ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"പതുക്കെ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ഉപയോക്താവ് മാറുക"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ഉപയോക്താവിനെ മാറ്റുക, <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> എന്നയാളാണ് നിലവിലുള്ള ഉപയോക്താവ്"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"നിലവിലെ ഉപയോക്താവ് <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml index d1dbd6dbf2d4..6b29affcfb6c 100644 --- a/packages/SystemUI/res/values-mn-rMN/strings.xml +++ b/packages/SystemUI/res/values-mn-rMN/strings.xml @@ -323,6 +323,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Зөвхөн\nхамгийн чухлыг"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Зөвхөн\nсэрүүлэг"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Хэрэглэгчийг сэлгэх"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Хэрэглэгчийг сэлгэх, одоогийн хэрэглэгч <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Одоогийн хэрэглэгч <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml index 2b9d953486b9..9d518a0c7008 100644 --- a/packages/SystemUI/res/values-mr-rIN/strings.xml +++ b/packages/SystemUI/res/values-mr-rIN/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवळ\nप्राधान्य"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवळ\nअलार्म"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) चार्ज होत आहे"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) वेगाने चार्ज होत आहे"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) हळूहळू चार्ज होत आहे"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"वापरकर्ता स्विच करा"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"वापरकर्ता स्विच करा, वर्तमान वापरकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"वर्तमान वापरकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml index 01f7edfd6066..10dca3e4545b 100644 --- a/packages/SystemUI/res/values-ms-rMY/strings.xml +++ b/packages/SystemUI/res/values-ms-rMY/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Keutamaan\nsahaja"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Penggera\nsahaja"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengecas cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengecas perlahan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Tukar pengguna"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Tukar pengguna, pengguna semasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Pengguna semasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml index d0eaccfaf550..adfd9f821f02 100644 --- a/packages/SystemUI/res/values-my-rMM/strings.xml +++ b/packages/SystemUI/res/values-my-rMM/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ဦးစားပေးမှု\nသာ"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"နှိုးစက်များ\nသာ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> အပြည့် အထိ) အားသွင်းနေ"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"လျှင်မြန်စွာအားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"နှေးကွေးစွာ အားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"အသုံးပြုသူကို ပြောင်းရန်၊ လက်ရှိ အသုံးပြုသူ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"လတ်တလော သုံးစွဲသူ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index e582039142db..ecfb7f24741f 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Bare\nPrioritet"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Bare\nalarmer"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Lader raskt (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lader sakte (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Bytt bruker"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Bytt bruker, gjeldende bruker er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Gjeldende bruker: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml index c3dc703e72ad..d997affa6b8a 100644 --- a/packages/SystemUI/res/values-ne-rNP/strings.xml +++ b/packages/SystemUI/res/values-ne-rNP/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"प्राथमिकता \nमात्र"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"अलार्महरू \nमात्र"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण भएसम्म)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"छिटो चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"बिस्तारै चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"प्रयोगकर्ता फेर्नुहोस्"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"प्रयोगकर्ता, हालको प्रयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> मा स्विच गर्नुहोस्"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"हालको प्रयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 79f3333ead53..c6bab06f0acd 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Alleen\nprioriteit"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alleen\nalarmen"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Snel opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langzaam opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Gebruiker wijzigen"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Schakelen tussen gebruikers, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml index ef3d2f3585bd..74e5fcb2096a 100644 --- a/packages/SystemUI/res/values-pa-rIN/strings.xml +++ b/packages/SystemUI/res/values-pa-rIN/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ਕੇਵਲ\nਤਰਜੀਹੀ"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ਕੇਵਲ\nਅਲਾਰਮ"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ਚਾਰਜਿੰਗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰਾ ਹੋਣ ਤੱਕ)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ਉਪਭੋਗਤਾ ਸਵਿਚ ਕਰੋ"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ਉਪਭੋਗਤਾ, ਵਰਤਮਾਨ ਉਪਭੋਗਤਾ ਸਵਿਚ ਕਰੋ<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ਮੌਜੂਦਾ ਉਪਭੋਗਤਾ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 8c2c5c430213..e04fd71a1b55 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tylko\npriorytetowe"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tylko\nalarmy"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Szybkie ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wolne ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Przełącz użytkownika"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Przełącz użytkownika. Bieżący użytkownik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Bieżący użytkownik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 3803b812013d..2a8e3ab51483 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Trocar usuário"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Alternar usuário. Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 12609c747e59..8453e5bc3106 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Apenas\nprioridade"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Apenas\nalarmes"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"A carregar rapid. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"A carregar lentam. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Mudar utilizador"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Mudar de utilizador; o utilizador atual é <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilizador atual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 3803b812013d..2a8e3ab51483 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Trocar usuário"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Alternar usuário. Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index bb8f2c3fe6b5..d85e791d0454 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -326,6 +326,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Numai\ncu prioritate"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Numai\nalarme"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Se încarcă rapid (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Se încarcă lent (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Comutați între utilizatori"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Schimbați utilizatorul (utilizator actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilizator actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 9609f40bdff8..39d861747968 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -329,6 +329,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Только\nважные"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Только\nбудильник"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Быстрая зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Медленная зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Сменить пользователя."</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Сменить аккаунт. Вход выполнен под именем <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>."</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Выбран аккаунт пользователя <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml index 9e7883422230..51bb047e5360 100644 --- a/packages/SystemUI/res/values-si-rLK/strings.xml +++ b/packages/SystemUI/res/values-si-rLK/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ප්රමුඛතා\nපමණි"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ඇඟවීම්\nපමණි"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ඉක්මනින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"සෙමින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"පරිශීලක මාරුව"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"පරිශීලකයා මාරු කරන්න,දැන් සිටින පරිශීලකයා <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"වත්මන් පරිශීලක <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 2e41b2969dd2..2886e36c9667 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -329,6 +329,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Iba\nprioritné"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Iba\nbudíky"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nabíja sa rýchlo (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Nabíja sa pomaly (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Prepnutie používateľa"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Prepnúť používateľa (súčasný používateľ: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuálny používateľ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 4dffcfa2bcd1..e325ef1b8771 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprednostno"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hitro polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Počasno polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Preklop med uporabniki"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Preklop med uporabniki, trenutni uporabnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Trenutni uporabnik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml index 20c342638aaa..5bcf941216eb 100644 --- a/packages/SystemUI/res/values-sq-rAL/strings.xml +++ b/packages/SystemUI/res/values-sq-rAL/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vetëm\nme prioritet"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vetëm\nalarmet"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Po ngarkohet (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> deri sa të mbushet)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Po ngarkon me shpejtësi (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Po ngarkon me ngadalë (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Ndërro përdorues"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Ndërro përdoruesin. Përdoruesi aktual është <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Përdoruesi aktual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 1dcde3a1b0bb..522b2af32221 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -326,6 +326,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприорит. прекиди"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Споро се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Замени корисника"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Промените корисника, актуелни корисник је <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Актуелни корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 0abeb1eb4d85..d91335c28279 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Endast\nprioriterade"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Endast\nalarm"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laddas snabbt (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laddas sakta (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Byt användare"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Byt användare. Aktuell användare: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuell användare <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index d000004c530a..1cf429380b34 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kipaumbele\npekee"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kengele\npekee"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ijae)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Inachaji kwa kasi (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Inachaji pole pole (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Badili mtumiaji"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Badili mtumiaji, mtumiaji wa sasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Mtumiaji wa sasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml index 3a62ad94f2c7..f084bc2c3ddb 100644 --- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -16,12 +16,6 @@ */ --> <resources> - <!-- Recent Applications parameters --> - <dimen name="status_bar_recents_app_label_width">190dip</dimen> - - <!-- The side padding for the task stack as a percentage of the width. --> - <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.25</item> - <fraction name="keyguard_clock_y_fraction_max">37%</fraction> <fraction name="keyguard_clock_y_fraction_min">20%</fraction> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index 83477c03d1e4..4f6d209b3f7a 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -32,9 +32,4 @@ <!-- Set to true to enable the user switcher on the keyguard. --> <bool name="config_keyguardUserSwitcher">true</bool> - - <!-- Transposes the search bar layout in landscape. --> - <bool name="recents_has_transposed_search_bar">true</bool> - <!-- Transposes the nav bar in landscape (only used for purposes of layout). --> - <bool name="recents_has_transposed_nav_bar">false</bool> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 1af4ab1f4b15..49dbac2f5f65 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -32,10 +32,6 @@ <!-- The width of the view containing the menu/ime navigation bar icons --> <dimen name="navigation_extra_key_width">48dip</dimen> - <!-- Size of application thumbnail --> - <dimen name="status_bar_recents_thumbnail_width">200dp</dimen> - <dimen name="status_bar_recents_thumbnail_height">177dp</dimen> - <!-- Minimum fraction of the screen that should be taken up by the notification panel. --> <item type="dimen" name="notification_panel_min_height_frac">40%</item> @@ -43,12 +39,6 @@ <!-- On tablets this is just the close_handle_height --> <dimen name="peek_height">@dimen/close_handle_height</dimen> - <!-- The side padding for the task stack as a percentage of the width. --> - <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.075</item> - - <!-- The height of the search bar space. --> - <dimen name="recents_search_bar_space_height">72dp</dimen> - <!-- The fraction of the screen height where the clock on the Keyguard has its center. The max value is used when no notifications are displaying, and the min value is when the highest possible number of notifications are showing. --> diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml index fbeadcd56da7..64e2760e7778 100644 --- a/packages/SystemUI/res/values-sw720dp/config.xml +++ b/packages/SystemUI/res/values-sw720dp/config.xml @@ -22,27 +22,8 @@ <resources> <integer name="status_bar_config_maxNotificationIcons">5</integer> - <!-- Whether we're using the tablet-optimized recents interface (we use this - value at runtime for some things) --> - <bool name="config_recents_interface_for_tablets">true</bool> - - <!-- Whether recents thumbnails should stretch in both x and y to fill their - ImageView --> - <bool name="config_recents_thumbnail_image_fits_to_xy">true</bool> - - <!-- Min alpha % that recent items will fade to while being dismissed --> - <integer name="config_recent_item_min_alpha">0</integer> - - <!-- Transposes the search bar layout in landscape --> - <bool name="recents_transpose_search_layout_with_orientation">false</bool> - <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow card. --> <integer name="keyguard_max_notification_count">5</integer> - - <!-- Transposes the search bar layout in landscape. --> - <bool name="recents_has_transposed_search_bar">false</bool> - <!-- Transposes the nav bar in landscape (only used for purposes of layout). --> - <bool name="recents_has_transposed_nav_bar">false</bool> </resources> diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml index dd158c2c70bc..7cee38140fe7 100644 --- a/packages/SystemUI/res/values-sw720dp/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp/dimens.xml @@ -29,42 +29,9 @@ <!-- Bottom margin (from display edge) for status bar panels --> <dimen name="panel_float">56dp</dimen> - <!-- Recent Applications parameters --> - <!-- How far the thumbnail for a recent app appears from left edge --> - <dimen name="status_bar_recents_thumbnail_left_margin">28dp</dimen> - <!-- Upper width limit for application icon --> - <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen> - <!-- Upper height limit for application icon --> - <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen> - - <!-- Size of application icon --> - <dimen name="status_bar_recents_thumbnail_width">208dp</dimen> - <dimen name="status_bar_recents_thumbnail_height">130dp</dimen> - - <!-- Width of recents panel --> - <dimen name="status_bar_recents_width">600dp</dimen> - <!-- Padding for text descriptions --> - <dimen name="status_bar_recents_text_description_padding">8dp</dimen> - <!-- Size of application label text --> - <dimen name="status_bar_recents_app_label_text_size">18dip</dimen> - <!-- Size of application description text --> - <dimen name="status_bar_recents_app_description_text_size">18dip</dimen> - <!-- Width of application label text --> - <dimen name="status_bar_recents_app_label_width">97dip</dimen> - <!-- Left margin for application label --> - <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen> - <!-- Size of fading edge for text --> - <dimen name="status_bar_recents_text_fading_edge_length">20dip</dimen> - <!-- Size of fading edge for scrolling --> - <dimen name="status_bar_recents_scroll_fading_edge_length">10dip</dimen> - <!-- The radius of the rounded corners on a task view. --> <dimen name="recents_task_view_rounded_corners_radius">3dp</dimen> - <!-- Where to place the app icon over the thumbnail --> - <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen> - <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen> - <!-- The fraction of the screen height where the clock on the Keyguard has its center. The max value is used when no notifications are displaying, and the min value is when the highest possible number of notifications are showing. --> diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml index 7b1ded375bac..670bccc71320 100644 --- a/packages/SystemUI/res/values-ta-rIN/strings.xml +++ b/packages/SystemUI/res/values-ta-rIN/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"முன்னுரிமைகள்\nமட்டும்"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"அலாரங்கள்\nமட்டும்"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"சார்ஜாகிறது (முழு சார்ஜிற்கு <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ஆகும்)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"வேகமாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"மெதுவாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"பயனரை மாற்று"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"பயனரை மாற்று, தற்போதைய பயனர் <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"தற்போதைய பயனர்: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml index 06762bd7ef4e..bbd9979d0585 100644 --- a/packages/SystemUI/res/values-te-rIN/strings.xml +++ b/packages/SystemUI/res/values-te-rIN/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ప్రాధాన్యమైనవి\nమాత్రమే"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"అలారాలు\nమాత్రమే"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ఛార్జ్ అవుతోంది (పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"వేగంగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"నెమ్మదిగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"వినియోగదారుని మార్చు"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"వినియోగదారుని మార్చు, ప్రస్తుత వినియోగదారు <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ప్రస్తుత వినియోగదారు <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 52c7af7f2f27..2486519f019f 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"เฉพาะเรื่อง\nสำคัญ"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"เฉพาะปลุก\nเท่านั้น"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"กำลังชาร์จอย่างรวดเร็ว (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"กำลังชาร์จอย่างช้าๆ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"สลับผู้ใช้"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"เปลี่ยนผู้ใช้จากผู้ใช้ปัจจุบัน <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ผู้ใช้ปัจจุบัน <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 66056d10dc64..3d1243e2f585 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priyoridad\nlang"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Mga alarm\nlang"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mabilis mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mabagal mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Magpalit ng user"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Magpalit ng user, kasalukuyang user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Kasalukuyang user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 49edb5746548..4dadfbc9e74f 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnızca\nöncelik"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnızca\nalarmlar"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hızlı şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Yavaş şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Kullanıcı değiştirme"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Kullanıcı değiştir. Geçerli kullanıcı: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Geçerli kullanıcı: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 9dde80178d2d..d158dbef756b 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Лише\nприорітетні"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Лише\nсигнали"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Швидке заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Повільне заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Змінити користувача"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Змінити користувача, поточний користувач – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Поточний користувач: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml index a4ef16acae62..f8d8c71e8f85 100644 --- a/packages/SystemUI/res/values-ur-rPK/strings.xml +++ b/packages/SystemUI/res/values-ur-rPK/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"صرف\nترجیحی"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"صرف\nالارمز"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"چارج ہو رہا ہے (مکمل ہونے تک <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> باقی ہیں)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"تیزی سے چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"آہستہ چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"صارف سوئچ کریں"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"صارف سوئچ کریں، موجودہ صارف <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"موجودہ صارف <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml index 04ec78b07526..018680956bdf 100644 --- a/packages/SystemUI/res/values-uz-rUZ/strings.xml +++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml @@ -82,7 +82,7 @@ <string name="accessibility_home" msgid="8217216074895377641">"Uyga"</string> <string name="accessibility_menu" msgid="316839303324695949">"Menyu"</string> <string name="accessibility_recent" msgid="5208608566793607626">"Umumiy nazar"</string> - <string name="accessibility_search_light" msgid="1103867596330271848">"Izlash"</string> + <string name="accessibility_search_light" msgid="1103867596330271848">"Qidirish"</string> <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string> <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string> <string name="accessibility_voice_assist_button" msgid="487611083884852965">"Ovozli yordam"</string> @@ -303,7 +303,7 @@ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>da to‘ladi"</string> <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Quvvat olmayapti"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tarmoq nazorat\nostida bo‘lishi mumkin"</string> - <string name="description_target_search" msgid="3091587249776033139">"Izlash"</string> + <string name="description_target_search" msgid="3091587249776033139">"Qidirish"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun yuqoriga suring."</string> <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun chapga suring."</string> <string name="zen_priority_introduction" msgid="3070506961866919502">"Turli ovoz va tebranishlar endi sizni bezovta qilmaydi. Biroq uyg‘otkich signallari, eslatmalar, tadbirlar haqidagi bildirishnomalar va siz tanlagan abonentlardan kelgan qo‘ng‘iroqlar bundan mustasno."</string> @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Faqat\nmuhimlar"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Faqat\nsignallar"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Quvvat olmoqda (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>da to‘ladi)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Tez quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sekin quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Foydalanuvchini almashtirish"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Foydalanuvchini o‘zgartirish. Joriy foydalanuvchi – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Joriy foydalanuvchi <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 460d57ae4410..49b5d1d29617 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Chỉ\nưu tiên"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Chỉ\nbáo thức"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sạc nhanh (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sạc chậm (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Chuyển đổi người dùng"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Chuyển người dùng, người dùng hiện tại <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Người dùng hiện tại <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 4d70f24b9ea8..93ed5ca876a5 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"仅限\n优先打扰"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"仅限\n闹钟"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充电(还需 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在慢速充电(还需 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切换用户"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切换用户,当前用户为<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"当前用户为<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index f7cac90e1522..219611133f50 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅限\n優先"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅限\n鬧鐘"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在緩慢充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切換使用者"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切換使用者,目前使用者是<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"目前的使用者是 <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 369172f36836..fe4fe0600254 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -327,6 +327,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅允許\n優先通知"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅允許\n鬧鐘"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"快速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"慢速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切換使用者"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切換使用者,目前使用者是<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"目前使用者是「<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>」"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 2a14a9f2b6d4..2f068af66dfc 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -325,6 +325,8 @@ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Okubalulekile\nkuphela"</string> <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ama-alamu\nkuphela"</string> <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string> + <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Iyashaja ngokushesha (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string> + <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Iyashaja kancane (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string> <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Shintsha umsebenzisi"</string> <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Shintsha umsebenzisi, umsebenzisi wamanje ngu-<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Umsebenzisi wamanje <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index da210843bd28..f40f0d9aecdb 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -24,11 +24,8 @@ <color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black --> <color name="system_bar_background_transparent">#00000000</color> <color name="notification_panel_solid_background">#ff000000</color> - <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable> - <color name="status_bar_recents_app_label_color">#ffffffff</color> <drawable name="status_bar_notification_row_background_color">#ff090909</drawable> <color name="notification_list_shadow_top">#80000000</color> - <drawable name="recents_callout_line">#99ffffff</drawable> <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable> <color name="batterymeter_frame_color">#4DFFFFFF</color><!-- 30% white --> <color name="batterymeter_charge_color">#FFFFFFFF</color> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 8da11488c482..1d1958943e94 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -20,15 +20,6 @@ <!-- These resources are around just to allow their values to be customized for different hardware and product builds. --> <resources> - - <!-- Whether we're using the tablet-optimized recents interface (we use this - value at runtime for some things) --> - <bool name="config_recents_interface_for_tablets">false</bool> - - <!-- Whether recents thumbnails should stretch in both x and y to fill their - ImageView --> - <bool name="config_recents_thumbnail_image_fits_to_xy">false</bool> - <!-- Whether recents should use hardware layers for its taskviews. This flag can be enabled for devices where the java drawing of round rects may be slow --> <bool name="config_recents_use_hardware_layers">false</bool> @@ -46,9 +37,6 @@ certain GPU's and thus can be turned off with only minimal visual impact. --> <bool name="config_notifications_round_rect_clipping">true</bool> - <!-- The theme to use for RecentsActivity. --> - <item type="style" name="config_recents_activity_theme">@style/RecentsTheme.Wallpaper</item> - <!-- Control whether status bar should distinguish HSPA data icon form UMTS data icon on devices --> <bool name="config_hspa_data_distinguishable">false</bool> @@ -92,10 +80,6 @@ <!-- The length of the vibration when the notification pops open. --> <integer name="one_finger_pop_duration_ms">10</integer> - <!-- Whether we're using the tablet-optimized recents interface (we use this - value at runtime for some things) --> - <integer name="status_bar_recents_bg_gradient_degrees">90</integer> - <!-- decay duration (from size_max -> size), in ms --> <integer name="navigation_bar_deadzone_hold">333</integer> <integer name="navigation_bar_deadzone_decay">333</integer> @@ -205,12 +189,6 @@ <!-- The delay to enforce between each alt-tab key press. --> <integer name="recents_alt_tab_key_delay">200</integer> - <!-- Transposes the search bar layout in landscape. --> - <bool name="recents_has_transposed_search_bar">true</bool> - - <!-- Transposes the nav bar in landscape (only used for purposes of layout). --> - <bool name="recents_has_transposed_nav_bar">true</bool> - <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. --> <integer name="recents_svelte_level">0</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 96a77256bc42..abfd86383776 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -16,45 +16,6 @@ */ --> <resources> - <!-- Recent Applications parameters --> - <!-- Upper width limit for application icon --> - <dimen name="status_bar_recents_app_icon_max_width">48dp</dimen> - <!-- Upper height limit for application icon --> - <dimen name="status_bar_recents_app_icon_max_height">48dp</dimen> - - <!-- Size of application thumbnail --> - <dimen name="status_bar_recents_thumbnail_width">164dp</dimen> - <dimen name="status_bar_recents_thumbnail_height">145dp</dimen> - <dimen name="status_bar_recents_thumbnail_bg_padding">4dp</dimen> - - <!-- Size of application label text --> - <dimen name="status_bar_recents_app_label_text_size">14dip</dimen> - <!-- Size of application description text --> - <dimen name="status_bar_recents_app_description_text_size">14dip</dimen> - <!-- Size of fading edge for text --> - <dimen name="status_bar_recents_text_fading_edge_length">20dip</dimen> - <!-- Size of fading edge for scrolling --> - <dimen name="status_bar_recents_scroll_fading_edge_length">10dip</dimen> - <!-- Margin between recents container and glow on the right --> - <dimen name="status_bar_recents_right_glow_margin">100dip</dimen> - <!-- How far the thumbnail for a recent app appears from left edge --> - <dimen name="status_bar_recents_thumbnail_left_margin">20dp</dimen> - <!-- Padding for text descriptions --> - <dimen name="status_bar_recents_text_description_padding">8dp</dimen> - <!-- Width of application label text --> - <dimen name="status_bar_recents_app_label_width">88dip</dimen> - <!-- Left margin of application label text --> - <dimen name="status_bar_recents_app_label_left_margin">0dip</dimen> - <!-- Padding between recents items --> - <dimen name="status_bar_recents_item_padding">0dip</dimen> - <!-- When recents first appears, how far the icon and label of the primary activity - travel --> - <dimen name="status_bar_recents_app_icon_translate_distance">35dip</dimen> - - <!-- Where to place the app icon over the thumbnail --> - <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen> - <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen> - <!-- Amount to offset bottom of notification peek window from top of status bar. --> <dimen name="peek_window_y_offset">-12dp</dimen> diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml index 351a1fdbda07..30ff7043f688 100644 --- a/packages/SystemUI/res/values/donottranslate.xml +++ b/packages/SystemUI/res/values/donottranslate.xml @@ -20,4 +20,10 @@ <!-- Date format for display: should match the lockscreen in /policy. --> <string name="system_ui_date_pattern">@*android:string/system_ui_date_pattern</string> + <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available --> + <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time</item> + + <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available --> + <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time</item> + </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index db1e688c1244..d567e9759966 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -793,6 +793,12 @@ <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]--> <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string> + <!-- Indication on the keyguard that is shown when the device is charging rapidly. Should match keyguard_plugged_in_charging_fast [CHAR LIMIT=40]--> + <string name="keyguard_indication_charging_time_fast">Charging rapidly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string> + + <!-- Indication on the keyguard that is shown when the device is charging slowly. Should match keyguard_plugged_in_charging_slowly [CHAR LIMIT=40]--> + <string name="keyguard_indication_charging_time_slowly">Charging slowly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string> + <!-- Related to user switcher --><skip/> <!-- Accessibility label for the button that opens the user switcher. --> diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java new file mode 100755 index 000000000000..3eb12711d1a2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui; + +import android.animation.ArgbEvaluator; +import android.annotation.Nullable; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.database.ContentObserver; +import android.graphics.*; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.provider.Settings; +import com.android.systemui.statusbar.policy.BatteryController; + +public class BatteryMeterDrawable extends Drawable implements DemoMode, + BatteryController.BatteryStateChangeCallback { + + private static final float ASPECT_RATIO = 9.5f / 14.5f; + public static final String TAG = BatteryMeterDrawable.class.getSimpleName(); + public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent"; + + private static final boolean SINGLE_DIGIT_PERCENT = false; + + private static final int FULL = 96; + + private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction + + private final int[] mColors; + + private boolean mShowPercent; + private float mButtonHeightFraction; + private float mSubpixelSmoothingLeft; + private float mSubpixelSmoothingRight; + private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint; + private float mTextHeight, mWarningTextHeight; + private int mIconTint = Color.WHITE; + + private int mHeight; + private int mWidth; + private String mWarningString; + private final int mCriticalLevel; + private int mChargeColor; + private final float[] mBoltPoints; + private final Path mBoltPath = new Path(); + + private final RectF mFrame = new RectF(); + private final RectF mButtonFrame = new RectF(); + private final RectF mBoltFrame = new RectF(); + + private final Path mShapePath = new Path(); + private final Path mClipPath = new Path(); + private final Path mTextPath = new Path(); + + private BatteryController mBatteryController; + private boolean mPowerSaveEnabled; + + private int mDarkModeBackgroundColor; + private int mDarkModeFillColor; + + private int mLightModeBackgroundColor; + private int mLightModeFillColor; + + private final SettingObserver mSettingObserver = new SettingObserver(); + + private final Context mContext; + private final Handler mHandler; + + private int mLevel = -1; + private boolean mPluggedIn; + private boolean mListening; + + public BatteryMeterDrawable(Context context, Handler handler, int frameColor) { + mContext = context; + mHandler = handler; + final Resources res = context.getResources(); + TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels); + TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values); + + final int N = levels.length(); + mColors = new int[2*N]; + for (int i=0; i<N; i++) { + mColors[2*i] = levels.getInt(i, 0); + mColors[2*i+1] = colors.getColor(i, 0); + } + levels.recycle(); + colors.recycle(); + updateShowPercent(); + mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol); + mCriticalLevel = mContext.getResources().getInteger( + com.android.internal.R.integer.config_criticalBatteryWarningLevel); + mButtonHeightFraction = context.getResources().getFraction( + R.fraction.battery_button_height_fraction, 1, 1); + mSubpixelSmoothingLeft = context.getResources().getFraction( + R.fraction.battery_subpixel_smoothing_left, 1, 1); + mSubpixelSmoothingRight = context.getResources().getFraction( + R.fraction.battery_subpixel_smoothing_right, 1, 1); + + mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mFramePaint.setColor(frameColor); + mFramePaint.setDither(true); + mFramePaint.setStrokeWidth(0); + mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE); + + mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mBatteryPaint.setDither(true); + mBatteryPaint.setStrokeWidth(0); + mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE); + + mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD); + mTextPaint.setTypeface(font); + mTextPaint.setTextAlign(Paint.Align.CENTER); + + mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mWarningTextPaint.setColor(mColors[1]); + font = Typeface.create("sans-serif", Typeface.BOLD); + mWarningTextPaint.setTypeface(font); + mWarningTextPaint.setTextAlign(Paint.Align.CENTER); + + mChargeColor = context.getColor(R.color.batterymeter_charge_color); + + mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color)); + mBoltPoints = loadBoltPoints(res); + + mDarkModeBackgroundColor = + context.getColor(R.color.dark_mode_icon_color_dual_tone_background); + mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill); + mLightModeBackgroundColor = + context.getColor(R.color.light_mode_icon_color_dual_tone_background); + mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill); + } + + public void startListening() { + mListening = true; + mContext.getContentResolver().registerContentObserver( + Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver); + if (mDemoMode) return; + mBatteryController.addStateChangedCallback(this); + } + + public void stopListening() { + mListening = false; + mContext.getContentResolver().unregisterContentObserver(mSettingObserver); + if (mDemoMode) return; + mBatteryController.removeStateChangedCallback(this); + } + + private void postInvalidate() { + mHandler.post(new Runnable() { + @Override + public void run() { + invalidateSelf(); + } + }); + } + + public void setBatteryController(BatteryController batteryController) { + mBatteryController = batteryController; + mPowerSaveEnabled = mBatteryController.isPowerSave(); + } + + @Override + public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { + mLevel = level; + mPluggedIn = pluggedIn; + + postInvalidate(); + } + + @Override + public void onPowerSaveChanged() { + mPowerSaveEnabled = mBatteryController.isPowerSave(); + invalidateSelf(); + } + + private static float[] loadBoltPoints(Resources res) { + final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points); + int maxX = 0, maxY = 0; + for (int i = 0; i < pts.length; i += 2) { + maxX = Math.max(maxX, pts[i]); + maxY = Math.max(maxY, pts[i + 1]); + } + final float[] ptsF = new float[pts.length]; + for (int i = 0; i < pts.length; i += 2) { + ptsF[i] = (float)pts[i] / maxX; + ptsF[i + 1] = (float)pts[i + 1] / maxY; + } + return ptsF; + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + super.setBounds(left, top, right, bottom); + mHeight = bottom - top; + mWidth = right - left; + mWarningTextPaint.setTextSize(mHeight * 0.75f); + mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent; + } + + private void updateShowPercent() { + mShowPercent = 0 != Settings.System.getInt(mContext.getContentResolver(), + SHOW_PERCENT_SETTING, 0); + } + + private int getColorForLevel(int percent) { + + // If we are in power save mode, always use the normal color. + if (mPowerSaveEnabled) { + return mColors[mColors.length-1]; + } + int thresh, color = 0; + for (int i=0; i<mColors.length; i+=2) { + thresh = mColors[i]; + color = mColors[i+1]; + if (percent <= thresh) { + + // Respect tinting for "normal" level + if (i == mColors.length-2) { + return mIconTint; + } else { + return color; + } + } + } + return color; + } + + public void setDarkIntensity(float darkIntensity) { + int backgroundColor = getBackgroundColor(darkIntensity); + int fillColor = getFillColor(darkIntensity); + mIconTint = fillColor; + mFramePaint.setColor(backgroundColor); + mBoltPaint.setColor(fillColor); + mChargeColor = fillColor; + invalidateSelf(); + } + + private int getBackgroundColor(float darkIntensity) { + return getColorForDarkIntensity( + darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor); + } + + private int getFillColor(float darkIntensity) { + return getColorForDarkIntensity( + darkIntensity, mLightModeFillColor, mDarkModeFillColor); + } + + private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) { + return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor); + } + + @Override + public void draw(Canvas c) { + final int level = mLevel; + + if (level == -1) return; + + float drawFrac = (float) level / 100f; + final int height = mHeight; + final int width = (int) (ASPECT_RATIO * mHeight); + int px = (mWidth - width) / 2; + + final int buttonHeight = (int) (height * mButtonHeightFraction); + + mFrame.set(0, 0, width, height); + mFrame.offset(px, 0); + + // button-frame: area above the battery body + mButtonFrame.set( + mFrame.left + Math.round(width * 0.25f), + mFrame.top, + mFrame.right - Math.round(width * 0.25f), + mFrame.top + buttonHeight); + + mButtonFrame.top += mSubpixelSmoothingLeft; + mButtonFrame.left += mSubpixelSmoothingLeft; + mButtonFrame.right -= mSubpixelSmoothingRight; + + // frame: battery body area + mFrame.top += buttonHeight; + mFrame.left += mSubpixelSmoothingLeft; + mFrame.top += mSubpixelSmoothingLeft; + mFrame.right -= mSubpixelSmoothingRight; + mFrame.bottom -= mSubpixelSmoothingRight; + + // set the battery charging color + mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level)); + + if (level >= FULL) { + drawFrac = 1f; + } else if (level <= mCriticalLevel) { + drawFrac = 0f; + } + + final float levelTop = drawFrac == 1f ? mButtonFrame.top + : (mFrame.top + (mFrame.height() * (1f - drawFrac))); + + // define the battery shape + mShapePath.reset(); + mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top); + mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top); + mShapePath.lineTo(mButtonFrame.right, mFrame.top); + mShapePath.lineTo(mFrame.right, mFrame.top); + mShapePath.lineTo(mFrame.right, mFrame.bottom); + mShapePath.lineTo(mFrame.left, mFrame.bottom); + mShapePath.lineTo(mFrame.left, mFrame.top); + mShapePath.lineTo(mButtonFrame.left, mFrame.top); + mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top); + + if (mPluggedIn) { + // define the bolt shape + final float bl = mFrame.left + mFrame.width() / 4.5f; + final float bt = mFrame.top + mFrame.height() / 6f; + final float br = mFrame.right - mFrame.width() / 7f; + final float bb = mFrame.bottom - mFrame.height() / 10f; + if (mBoltFrame.left != bl || mBoltFrame.top != bt + || mBoltFrame.right != br || mBoltFrame.bottom != bb) { + mBoltFrame.set(bl, bt, br, bb); + mBoltPath.reset(); + mBoltPath.moveTo( + mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(), + mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height()); + for (int i = 2; i < mBoltPoints.length; i += 2) { + mBoltPath.lineTo( + mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(), + mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height()); + } + mBoltPath.lineTo( + mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(), + mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height()); + } + + float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top); + boltPct = Math.min(Math.max(boltPct, 0), 1); + if (boltPct <= BOLT_LEVEL_THRESHOLD) { + // draw the bolt if opaque + c.drawPath(mBoltPath, mBoltPaint); + } else { + // otherwise cut the bolt out of the overall shape + mShapePath.op(mBoltPath, Path.Op.DIFFERENCE); + } + } + + // compute percentage text + boolean pctOpaque = false; + float pctX = 0, pctY = 0; + String pctText = null; + if (!mPluggedIn && level > mCriticalLevel && mShowPercent) { + mTextPaint.setColor(getColorForLevel(level)); + mTextPaint.setTextSize(height * + (SINGLE_DIGIT_PERCENT ? 0.75f + : (mLevel == 100 ? 0.38f : 0.5f))); + mTextHeight = -mTextPaint.getFontMetrics().ascent; + pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level); + pctX = mWidth * 0.5f; + pctY = (mHeight + mTextHeight) * 0.47f; + pctOpaque = levelTop > pctY; + if (!pctOpaque) { + mTextPath.reset(); + mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath); + // cut the percentage text out of the overall shape + mShapePath.op(mTextPath, Path.Op.DIFFERENCE); + } + } + + // draw the battery shape background + c.drawPath(mShapePath, mFramePaint); + + // draw the battery shape, clipped to charging level + mFrame.top = levelTop; + mClipPath.reset(); + mClipPath.addRect(mFrame, Path.Direction.CCW); + mShapePath.op(mClipPath, Path.Op.INTERSECT); + c.drawPath(mShapePath, mBatteryPaint); + + if (!mPluggedIn) { + if (level <= mCriticalLevel) { + // draw the warning text + final float x = mWidth * 0.5f; + final float y = (mHeight + mWarningTextHeight) * 0.48f; + c.drawText(mWarningString, x, y, mWarningTextPaint); + } else if (pctOpaque) { + // draw the percentage text + c.drawText(pctText, pctX, pctY, mTextPaint); + } + } + } + + // Some stuff required by Drawable. + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + } + + @Override + public int getOpacity() { + return 0; + } + + private boolean mDemoMode; + + @Override + public void dispatchDemoCommand(String command, Bundle args) { + if (!mDemoMode && command.equals(COMMAND_ENTER)) { + mBatteryController.removeStateChangedCallback(this); + mDemoMode = true; + if (mListening) { + mBatteryController.removeStateChangedCallback(this); + } + } else if (mDemoMode && command.equals(COMMAND_EXIT)) { + mDemoMode = false; + postInvalidate(); + if (mListening) { + mBatteryController.addStateChangedCallback(this); + } + } else if (mDemoMode && command.equals(COMMAND_BATTERY)) { + String level = args.getString("level"); + String plugged = args.getString("plugged"); + if (level != null) { + mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100); + } + if (plugged != null) { + mPluggedIn = Boolean.parseBoolean(plugged); + } + postInvalidate(); + } + } + + private final class SettingObserver extends ContentObserver { + public SettingObserver() { + super(new Handler()); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + super.onChange(selfChange, uri); + updateShowPercent(); + postInvalidate(); + } + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index 95b58e5e527f..6cb8da4a1016 100755..100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -13,82 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.systemui; -import android.animation.ArgbEvaluator; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; import android.content.res.TypedArray; -import android.database.ContentObserver; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.RectF; -import android.graphics.Typeface; -import android.net.Uri; -import android.os.BatteryManager; -import android.os.Bundle; import android.os.Handler; -import android.provider.Settings; import android.util.AttributeSet; -import android.view.View; - +import android.widget.ImageView; import com.android.systemui.statusbar.policy.BatteryController; -public class BatteryMeterView extends View implements DemoMode, - BatteryController.BatteryStateChangeCallback { - public static final String TAG = BatteryMeterView.class.getSimpleName(); - public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST"; - public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent"; - - private static final boolean SINGLE_DIGIT_PERCENT = false; - - private static final int FULL = 96; - - private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction - - private final int[] mColors; - - private boolean mShowPercent; - private float mButtonHeightFraction; - private float mSubpixelSmoothingLeft; - private float mSubpixelSmoothingRight; - private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint; - private float mTextHeight, mWarningTextHeight; - private int mIconTint = Color.WHITE; - - private int mHeight; - private int mWidth; - private String mWarningString; - private final int mCriticalLevel; - private int mChargeColor; - private final float[] mBoltPoints; - private final Path mBoltPath = new Path(); - - private final RectF mFrame = new RectF(); - private final RectF mButtonFrame = new RectF(); - private final RectF mBoltFrame = new RectF(); - - private final Path mShapePath = new Path(); - private final Path mClipPath = new Path(); - private final Path mTextPath = new Path(); +public class BatteryMeterView extends ImageView implements BatteryController.BatteryStateChangeCallback { + private final BatteryMeterDrawable mDrawable; private BatteryController mBatteryController; - private boolean mPowerSaveEnabled; - - private int mDarkModeBackgroundColor; - private int mDarkModeFillColor; - - private int mLightModeBackgroundColor; - private int mLightModeFillColor; - - private BatteryTracker mTracker = new BatteryTracker(); - private final SettingObserver mSettingObserver = new SettingObserver(); public BatteryMeterView(Context context) { this(context, null, 0); @@ -101,443 +38,52 @@ public class BatteryMeterView extends View implements DemoMode, public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - final Resources res = context.getResources(); TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView, defStyle, 0); final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor, context.getColor(R.color.batterymeter_frame_color)); - TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels); - TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values); - - final int N = levels.length(); - mColors = new int[2*N]; - for (int i=0; i<N; i++) { - mColors[2*i] = levels.getInt(i, 0); - mColors[2*i+1] = colors.getColor(i, 0); - } - levels.recycle(); - colors.recycle(); + mDrawable = new BatteryMeterDrawable(context, new Handler(), frameColor); atts.recycle(); - updateShowPercent(); - mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol); - mCriticalLevel = mContext.getResources().getInteger( - com.android.internal.R.integer.config_criticalBatteryWarningLevel); - mButtonHeightFraction = context.getResources().getFraction( - R.fraction.battery_button_height_fraction, 1, 1); - mSubpixelSmoothingLeft = context.getResources().getFraction( - R.fraction.battery_subpixel_smoothing_left, 1, 1); - mSubpixelSmoothingRight = context.getResources().getFraction( - R.fraction.battery_subpixel_smoothing_right, 1, 1); - - mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mFramePaint.setColor(frameColor); - mFramePaint.setDither(true); - mFramePaint.setStrokeWidth(0); - mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE); - - mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBatteryPaint.setDither(true); - mBatteryPaint.setStrokeWidth(0); - mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE); - mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD); - mTextPaint.setTypeface(font); - mTextPaint.setTextAlign(Paint.Align.CENTER); - - mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mWarningTextPaint.setColor(mColors[1]); - font = Typeface.create("sans-serif", Typeface.BOLD); - mWarningTextPaint.setTypeface(font); - mWarningTextPaint.setTextAlign(Paint.Align.CENTER); - - mChargeColor = context.getColor(R.color.batterymeter_charge_color); - - mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color)); - mBoltPoints = loadBoltPoints(res); + setImageDrawable(mDrawable); + } - mDarkModeBackgroundColor = - context.getColor(R.color.dark_mode_icon_color_dual_tone_background); - mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill); - mLightModeBackgroundColor = - context.getColor(R.color.light_mode_icon_color_dual_tone_background); - mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill); + @Override + public boolean hasOverlappingRendering() { + return false; } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); - - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_BATTERY_CHANGED); - filter.addAction(ACTION_LEVEL_TEST); - final Intent sticky = getContext().registerReceiver(mTracker, filter); - if (sticky != null) { - // preload the battery level - mTracker.onReceive(getContext(), sticky); - } mBatteryController.addStateChangedCallback(this); - getContext().getContentResolver().registerContentObserver( - Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver); + mDrawable.startListening(); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); - - getContext().unregisterReceiver(mTracker); mBatteryController.removeStateChangedCallback(this); - getContext().getContentResolver().unregisterContentObserver(mSettingObserver); - } - - public void setBatteryController(BatteryController batteryController) { - mBatteryController = batteryController; - mPowerSaveEnabled = mBatteryController.isPowerSave(); + mDrawable.stopListening(); } @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { - // TODO: Use this callback instead of own broadcast receiver. + setContentDescription( + getContext().getString(R.string.accessibility_battery_level, level)); } @Override public void onPowerSaveChanged() { - mPowerSaveEnabled = mBatteryController.isPowerSave(); - invalidate(); - } - private static float[] loadBoltPoints(Resources res) { - final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points); - int maxX = 0, maxY = 0; - for (int i = 0; i < pts.length; i += 2) { - maxX = Math.max(maxX, pts[i]); - maxY = Math.max(maxY, pts[i + 1]); - } - final float[] ptsF = new float[pts.length]; - for (int i = 0; i < pts.length; i += 2) { - ptsF[i] = (float)pts[i] / maxX; - ptsF[i + 1] = (float)pts[i + 1] / maxY; - } - return ptsF; } - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - mHeight = h; - mWidth = w; - mWarningTextPaint.setTextSize(h * 0.75f); - mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent; + public void setBatteryController(BatteryController mBatteryController) { + this.mBatteryController = mBatteryController; + mDrawable.setBatteryController(mBatteryController); } - private void updateShowPercent() { - mShowPercent = 0 != Settings.System.getInt(getContext().getContentResolver(), - SHOW_PERCENT_SETTING, 0); + public void setDarkIntensity(float f) { + mDrawable.setDarkIntensity(f); } - - private int getColorForLevel(int percent) { - - // If we are in power save mode, always use the normal color. - if (mPowerSaveEnabled) { - return mColors[mColors.length-1]; - } - int thresh, color = 0; - for (int i=0; i<mColors.length; i+=2) { - thresh = mColors[i]; - color = mColors[i+1]; - if (percent <= thresh) { - - // Respect tinting for "normal" level - if (i == mColors.length-2) { - return mIconTint; - } else { - return color; - } - } - } - return color; - } - - public void setDarkIntensity(float darkIntensity) { - int backgroundColor = getBackgroundColor(darkIntensity); - int fillColor = getFillColor(darkIntensity); - mIconTint = fillColor; - mFramePaint.setColor(backgroundColor); - mBoltPaint.setColor(fillColor); - mChargeColor = fillColor; - invalidate(); - } - - private int getBackgroundColor(float darkIntensity) { - return getColorForDarkIntensity( - darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor); - } - - private int getFillColor(float darkIntensity) { - return getColorForDarkIntensity( - darkIntensity, mLightModeFillColor, mDarkModeFillColor); - } - - private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) { - return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor); - } - - @Override - public void draw(Canvas c) { - BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker; - final int level = tracker.level; - - if (level == BatteryTracker.UNKNOWN_LEVEL) return; - - float drawFrac = (float) level / 100f; - final int pt = getPaddingTop(); - final int pl = getPaddingLeft(); - final int pr = getPaddingRight(); - final int pb = getPaddingBottom(); - final int height = mHeight - pt - pb; - final int width = mWidth - pl - pr; - - final int buttonHeight = (int) (height * mButtonHeightFraction); - - mFrame.set(0, 0, width, height); - mFrame.offset(pl, pt); - - // button-frame: area above the battery body - mButtonFrame.set( - mFrame.left + Math.round(width * 0.25f), - mFrame.top, - mFrame.right - Math.round(width * 0.25f), - mFrame.top + buttonHeight); - - mButtonFrame.top += mSubpixelSmoothingLeft; - mButtonFrame.left += mSubpixelSmoothingLeft; - mButtonFrame.right -= mSubpixelSmoothingRight; - - // frame: battery body area - mFrame.top += buttonHeight; - mFrame.left += mSubpixelSmoothingLeft; - mFrame.top += mSubpixelSmoothingLeft; - mFrame.right -= mSubpixelSmoothingRight; - mFrame.bottom -= mSubpixelSmoothingRight; - - // set the battery charging color - mBatteryPaint.setColor(tracker.plugged ? mChargeColor : getColorForLevel(level)); - - if (level >= FULL) { - drawFrac = 1f; - } else if (level <= mCriticalLevel) { - drawFrac = 0f; - } - - final float levelTop = drawFrac == 1f ? mButtonFrame.top - : (mFrame.top + (mFrame.height() * (1f - drawFrac))); - - // define the battery shape - mShapePath.reset(); - mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top); - mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top); - mShapePath.lineTo(mButtonFrame.right, mFrame.top); - mShapePath.lineTo(mFrame.right, mFrame.top); - mShapePath.lineTo(mFrame.right, mFrame.bottom); - mShapePath.lineTo(mFrame.left, mFrame.bottom); - mShapePath.lineTo(mFrame.left, mFrame.top); - mShapePath.lineTo(mButtonFrame.left, mFrame.top); - mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top); - - if (tracker.plugged) { - // define the bolt shape - final float bl = mFrame.left + mFrame.width() / 4.5f; - final float bt = mFrame.top + mFrame.height() / 6f; - final float br = mFrame.right - mFrame.width() / 7f; - final float bb = mFrame.bottom - mFrame.height() / 10f; - if (mBoltFrame.left != bl || mBoltFrame.top != bt - || mBoltFrame.right != br || mBoltFrame.bottom != bb) { - mBoltFrame.set(bl, bt, br, bb); - mBoltPath.reset(); - mBoltPath.moveTo( - mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(), - mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height()); - for (int i = 2; i < mBoltPoints.length; i += 2) { - mBoltPath.lineTo( - mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(), - mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height()); - } - mBoltPath.lineTo( - mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(), - mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height()); - } - - float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top); - boltPct = Math.min(Math.max(boltPct, 0), 1); - if (boltPct <= BOLT_LEVEL_THRESHOLD) { - // draw the bolt if opaque - c.drawPath(mBoltPath, mBoltPaint); - } else { - // otherwise cut the bolt out of the overall shape - mShapePath.op(mBoltPath, Path.Op.DIFFERENCE); - } - } - - // compute percentage text - boolean pctOpaque = false; - float pctX = 0, pctY = 0; - String pctText = null; - if (!tracker.plugged && level > mCriticalLevel && mShowPercent) { - mTextPaint.setColor(getColorForLevel(level)); - mTextPaint.setTextSize(height * - (SINGLE_DIGIT_PERCENT ? 0.75f - : (tracker.level == 100 ? 0.38f : 0.5f))); - mTextHeight = -mTextPaint.getFontMetrics().ascent; - pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level); - pctX = mWidth * 0.5f; - pctY = (mHeight + mTextHeight) * 0.47f; - pctOpaque = levelTop > pctY; - if (!pctOpaque) { - mTextPath.reset(); - mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath); - // cut the percentage text out of the overall shape - mShapePath.op(mTextPath, Path.Op.DIFFERENCE); - } - } - - // draw the battery shape background - c.drawPath(mShapePath, mFramePaint); - - // draw the battery shape, clipped to charging level - mFrame.top = levelTop; - mClipPath.reset(); - mClipPath.addRect(mFrame, Path.Direction.CCW); - mShapePath.op(mClipPath, Path.Op.INTERSECT); - c.drawPath(mShapePath, mBatteryPaint); - - if (!tracker.plugged) { - if (level <= mCriticalLevel) { - // draw the warning text - final float x = mWidth * 0.5f; - final float y = (mHeight + mWarningTextHeight) * 0.48f; - c.drawText(mWarningString, x, y, mWarningTextPaint); - } else if (pctOpaque) { - // draw the percentage text - c.drawText(pctText, pctX, pctY, mTextPaint); - } - } - } - - @Override - public boolean hasOverlappingRendering() { - return false; - } - - private boolean mDemoMode; - private BatteryTracker mDemoTracker = new BatteryTracker(); - - @Override - public void dispatchDemoCommand(String command, Bundle args) { - if (!mDemoMode && command.equals(COMMAND_ENTER)) { - mDemoMode = true; - mDemoTracker.level = mTracker.level; - mDemoTracker.plugged = mTracker.plugged; - } else if (mDemoMode && command.equals(COMMAND_EXIT)) { - mDemoMode = false; - postInvalidate(); - } else if (mDemoMode && command.equals(COMMAND_BATTERY)) { - String level = args.getString("level"); - String plugged = args.getString("plugged"); - if (level != null) { - mDemoTracker.level = Math.min(Math.max(Integer.parseInt(level), 0), 100); - } - if (plugged != null) { - mDemoTracker.plugged = Boolean.parseBoolean(plugged); - } - postInvalidate(); - } - } - - private final class BatteryTracker extends BroadcastReceiver { - public static final int UNKNOWN_LEVEL = -1; - - // current battery status - int level = UNKNOWN_LEVEL; - String percentStr; - int plugType; - boolean plugged; - int health; - int status; - String technology; - int voltage; - int temperature; - boolean testmode = false; - - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - if (testmode && ! intent.getBooleanExtra("testmode", false)) return; - - level = (int)(100f - * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) - / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)); - - plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); - plugged = plugType != 0; - health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH, - BatteryManager.BATTERY_HEALTH_UNKNOWN); - status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, - BatteryManager.BATTERY_STATUS_UNKNOWN); - technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY); - voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0); - temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0); - - setContentDescription( - context.getString(R.string.accessibility_battery_level, level)); - postInvalidate(); - } else if (action.equals(ACTION_LEVEL_TEST)) { - testmode = true; - post(new Runnable() { - int curLevel = 0; - int incr = 1; - int saveLevel = level; - int savePlugged = plugType; - Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED); - @Override - public void run() { - if (curLevel < 0) { - testmode = false; - dummy.putExtra("level", saveLevel); - dummy.putExtra("plugged", savePlugged); - dummy.putExtra("testmode", false); - } else { - dummy.putExtra("level", curLevel); - dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC - : 0); - dummy.putExtra("testmode", true); - } - getContext().sendBroadcast(dummy); - - if (!testmode) return; - - curLevel += incr; - if (curLevel == 100) { - incr *= -1; - } - postDelayed(this, 200); - } - }); - } - } - } - - private final class SettingObserver extends ContentObserver { - public SettingObserver() { - super(new Handler()); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - super.onChange(selfChange, uri); - updateShowPercent(); - postInvalidate(); - } - } - } diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 33f6564b948a..620732442659 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -34,6 +34,8 @@ import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; +import com.android.systemui.classifier.FalsingManager; + public class SwipeHelper implements Gefingerpoken { static final String TAG = "com.android.systemui.SwipeHelper"; private static final boolean DEBUG = false; @@ -67,6 +69,7 @@ public class SwipeHelper implements Gefingerpoken { private Handler mHandler; private int mSwipeDirection; private VelocityTracker mVelocityTracker; + private FalsingManager mFalsingManager; private float mInitialTouchPos; private boolean mDragging; @@ -97,6 +100,7 @@ public class SwipeHelper implements Gefingerpoken { android.R.interpolator.fast_out_linear_in); mFalsingThreshold = context.getResources().getDimensionPixelSize( R.dimen.swipe_helper_falsing_threshold); + mFalsingManager = FalsingManager.getInstance(context); } public void setLongPressListener(LongPressListener listener) { @@ -449,8 +453,13 @@ public class SwipeHelper implements Gefingerpoken { boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) && (Math.abs(velocity) > Math.abs(perpendicularVelocity)) && (velocity > 0) == (getTranslation(mCurrAnimView) > 0); - boolean falsingDetected = mCallback.isAntiFalsingNeeded() - && !mTouchAboveFalsingThreshold; + boolean falsingDetected = mCallback.isAntiFalsingNeeded(); + + if (mFalsingManager.isClassiferEnabled()) { + falsingDetected = falsingDetected && mFalsingManager.isFalseTouch(); + } else { + falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold; + } boolean dismissChild = mCallback.canChildBeDismissed(mCurrView) && !falsingDetected && (childSwipedFastEnough || childSwipedFarEnough) diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 74490098af16..5bf251b57af1 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -159,7 +159,9 @@ public class SystemUIApplication extends Application { if (mServicesStarted) { int len = mServices.length; for (int i = 0; i < len; i++) { - mServices[i].onConfigurationChanged(newConfig); + if (mServices[i] != null) { + mServices[i].onConfigurationChanged(newConfig); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java new file mode 100644 index 000000000000..86bea873b737 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.view.MotionEvent; + +import java.util.HashMap; + +/** + * A classifier which looks at the speed and distance between successive points of a Stroke. + * It looks at two consecutive speeds between two points and calculates the ratio between them. + * The final result is the maximum of these values. It does the same for distances. If some speed + * or distance is equal to zero then the ratio between this and the next part is not calculated. To + * the duration of each part there is added one nanosecond so that it is always possible to + * calculate the speed of a part. + */ +public class AccelerationClassifier extends StrokeClassifier { + private final HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); + + public AccelerationClassifier(ClassifierData classifierData) { + mClassifierData = classifierData; + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mStrokeMap.clear(); + } + + for (int i = 0; i < event.getPointerCount(); i++) { + Stroke stroke = mClassifierData.getStroke(event.getPointerId(i)); + Point point = stroke.getPoints().get(stroke.getPoints().size() - 1); + if (mStrokeMap.get(stroke) == null) { + mStrokeMap.put(stroke, new Data(point)); + } else { + mStrokeMap.get(stroke).addPoint(point); + } + } + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + Data data = mStrokeMap.get(stroke); + return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio) + + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio); + } + + private static class Data { + public Point previousPoint; + public float previousSpeed; + public float previousDistance; + public float maxSpeedRatio; + public float maxDistanceRatio; + + public Data(Point point) { + previousPoint = point; + previousSpeed = previousDistance = 0.0f; + maxDistanceRatio = maxSpeedRatio = 0.0f; + } + + public void addPoint(Point point) { + float distance = previousPoint.dist(point); + float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1); + float speed = distance / duration; + if (previousDistance != 0.0f) { + maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance); + } + + if (previousSpeed != 0.0f) { + maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed); + } + + previousDistance = distance; + previousSpeed = speed; + previousPoint = point; + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java new file mode 100644 index 000000000000..a6ebc0bf0a9f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.view.MotionEvent; + +import java.lang.Math; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * A classifier which calculates the variance of differences between successive angles in a stroke. + * For each stroke it keeps its last three points. If some successive points are the same, it + * ignores the repetitions. If a new point is added, the classifier calculates the angle between + * the last three points. After that, it calculates the difference between this angle and the + * previously calculated angle. Then it calculates the variance of the differences from a stroke. + * To the differences there is artificially added value 0.0 and the difference between the first + * angle and PI (angles are in radians). It helps with strokes which have few points and punishes + * more strokes which are not smooth. + * + * This classifier also tries to split the stroke into two parts in the place in which the biggest + * angle is. It calculates the angle variance of the two parts and sums them up. The reason the + * classifier is doing this, is because some human swipes at the beginning go for a moment in one + * direction and then they rapidly change direction for the rest of the stroke (like a tick). The + * final result is the minimum of angle variance of the whole stroke and the sum of angle variances + * of the two parts split up. The classifier tries the tick option only if the first part is + * shorter than the second part. + * + * Additionally, the classifier classifies the angles as left angles (those angles which value is + * in [0.0, PI - ANGLE_DEVIATION) interval), straight angles + * ([PI - ANGLE_DEVIATION, PI + ANGLE_DEVIATION] interval) and right angles + * ((PI + ANGLE_DEVIATION, 2 * PI) interval) and then calculates the percentage of angles which are + * in the same direction (straight angles can be left angels or right angles) + */ +public class AnglesClassifier extends StrokeClassifier { + private HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); + + public AnglesClassifier(ClassifierData classifierData) { + mClassifierData = classifierData; + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mStrokeMap.clear(); + } + + for (int i = 0; i < event.getPointerCount(); i++) { + Stroke stroke = mClassifierData.getStroke(event.getPointerId(i)); + + if (mStrokeMap.get(stroke) == null) { + mStrokeMap.put(stroke, new Data()); + } + mStrokeMap.get(stroke).addPoint(stroke.getPoints().get(stroke.getPoints().size() - 1)); + } + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + Data data = mStrokeMap.get(stroke); + return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance()) + + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage()); + } + + private static class Data { + private final float ANGLE_DEVIATION = (float) Math.PI / 20.0f; + + private List<Point> mLastThreePoints = new ArrayList<>(); + private float mFirstAngleVariance; + private float mPreviousAngle; + private float mBiggestAngle; + private float mSumSquares; + private float mSecondSumSquares; + private float mSum; + private float mSecondSum; + private float mCount; + private float mSecondCount; + private float mFirstLength; + private float mLength; + private float mAnglesCount; + private float mLeftAngles; + private float mRightAngles; + private float mStraightAngles; + + public Data() { + mFirstAngleVariance = 0.0f; + mPreviousAngle = (float) Math.PI; + mBiggestAngle = 0.0f; + mSumSquares = mSecondSumSquares = 0.0f; + mSum = mSecondSum = 0.0f; + mCount = mSecondCount = 1.0f; + mLength = mFirstLength = 0.0f; + mAnglesCount = mLeftAngles = mRightAngles = mStraightAngles = 0.0f; + } + + public void addPoint(Point point) { + // Checking if the added point is different than the previously added point + // Repetitions are being ignored so that proper angles are calculated. + if (mLastThreePoints.isEmpty() + || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(point)) { + if (!mLastThreePoints.isEmpty()) { + mLength += mLastThreePoints.get(mLastThreePoints.size() - 1).dist(point); + } + mLastThreePoints.add(point); + if (mLastThreePoints.size() == 4) { + mLastThreePoints.remove(0); + + float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0), + mLastThreePoints.get(2)); + + mAnglesCount++; + if (angle < Math.PI - ANGLE_DEVIATION) { + mLeftAngles++; + } else if (angle <= Math.PI + ANGLE_DEVIATION) { + mStraightAngles++; + } else { + mRightAngles++; + } + + float difference = angle - mPreviousAngle; + + // If this is the biggest angle of the stroke so then we save the value of + // the angle variance so far and start to count the values for the angle + // variance of the second part. + if (mBiggestAngle < angle) { + mBiggestAngle = angle; + mFirstLength = mLength; + mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount); + mSecondSumSquares = 0.0f; + mSecondSum = 0.0f; + mSecondCount = 1.0f; + } else { + mSecondSum += difference; + mSecondSumSquares += difference * difference; + mSecondCount += 1.0; + } + + mSum += difference; + mSumSquares += difference * difference; + mCount += 1.0; + mPreviousAngle = angle; + } + } + } + + public float getAnglesVariance(float sumSquares, float sum, float count) { + return sumSquares / count - (sum / count) * (sum / count); + } + + public float getAnglesVariance() { + float anglesVariance = getAnglesVariance(mSumSquares, mSum, mCount); + if (mFirstLength < mLength / 2f) { + anglesVariance = Math.min(anglesVariance, mFirstAngleVariance + + getAnglesVariance(mSecondSumSquares, mSecondSum, mSecondCount)); + } + return anglesVariance; + } + + public float getAnglesPercentage() { + if (mAnglesCount == 0.0f) { + return 1.0f; + } + return (Math.max(mLeftAngles, mRightAngles) + mStraightAngles) / mAnglesCount; + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java new file mode 100644 index 000000000000..a0ceb2958c33 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class AnglesPercentageEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 1.00) evaluation++; + if (value < 0.95) evaluation++; + if (value < 0.90) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java deleted file mode 100644 index 5cd914f06828..000000000000 --- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.classifier; - -import android.hardware.SensorEvent; -import android.view.MotionEvent; - -import java.lang.Math; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * A classifier which calculates the variance of differences between successive angles in a stroke. - * For each stroke it keeps its last three points. If some successive points are the same, it ignores - * the repetitions. If a new point is added, the classifier calculates the angle between the last - * three points. After that it calculates the difference between this angle and the previously - * calculated angle. The return value of the classifier is the variance of the differences - * from a stroke. If there are multiple strokes created at once, the classifier sums up the - * variances of all the strokes. Also the value is multiplied by HISTORY_FACTOR after each - * INTERVAL milliseconds. - */ -public class AnglesVarianceClassifier extends Classifier { - private final float INTERVAL = 10.0f; - private final float CLEAR_HISTORY = 500f; - private final float HISTORY_FACTOR = 0.9f; - - private HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); - private float mValue; - private long mLastUpdate; - - public AnglesVarianceClassifier(ClassifierData classifierData) { - mClassifierData = classifierData; - mValue = 0.0f; - mLastUpdate = System.currentTimeMillis(); - } - - @Override - public void onTouchEvent(MotionEvent event) { - int action = event.getActionMasked(); - - if (action == MotionEvent.ACTION_DOWN) { - mStrokeMap.clear(); - } - - for (int i = 0; i < event.getPointerCount(); i++) { - Stroke stroke = mClassifierData.getStroke(event.getPointerId(i)); - - if (mStrokeMap.get(stroke) == null) { - mStrokeMap.put(stroke, new Data()); - } - mStrokeMap.get(stroke).addPoint(stroke.getPoints().get(stroke.getPoints().size() - 1)); - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL - || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { - decayValue(); - mValue += mStrokeMap.get(stroke).getAnglesVariance(); - } - } - } - - /** - * Decreases mValue through time - */ - private void decayValue() { - long currentTimeMillis = System.currentTimeMillis(); - if (currentTimeMillis - mLastUpdate > CLEAR_HISTORY) { - mValue = 0.0f; - } else { - mValue *= Math.pow(HISTORY_FACTOR, (float) (currentTimeMillis - mLastUpdate) / INTERVAL); - } - mLastUpdate = currentTimeMillis; - } - - @Override - public void onSensorChanged(SensorEvent event) { - } - - @Override - public float getFalseTouchEvaluation(int type) { - decayValue(); - float currentValue = 0.0f; - for (Data data: mStrokeMap.values()) { - currentValue += data.getAnglesVariance(); - } - return (float) (mValue + currentValue); - } - - private class Data { - private List<Point> mLastThreePoints = new ArrayList<>(); - private float mPreviousAngle; - private float mSumSquares; - private float mSum; - private float mCount; - - public Data() { - mPreviousAngle = (float) Math.PI; - mSumSquares = 0.0f; - mSum = 0.0f; - mCount = 1.0f; - } - - public void addPoint(Point point) { - // Checking if the added point is different than the previously added point - // Repetitions are being ignored so that proper angles are calculated. - if (mLastThreePoints.isEmpty() - || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(point)) { - mLastThreePoints.add(point); - if (mLastThreePoints.size() == 4) { - mLastThreePoints.remove(0); - - float angle = getAngle(mLastThreePoints.get(0), mLastThreePoints.get(1), - mLastThreePoints.get(2)); - - float difference = angle - mPreviousAngle; - mSum += difference; - mSumSquares += difference * difference; - mCount += 1.0; - mPreviousAngle = angle; - } - } - } - - private float getAngle(Point a, Point b, Point c) { - float dist1 = a.dist(b); - float dist2 = b.dist(c); - float crossProduct = b.crossProduct(a, c); - float dotProduct = b.dotProduct(a, c); - float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2)); - float angle = (float) Math.acos(cos); - if (crossProduct < 0.0) { - angle = 2.0f * (float) Math.PI - angle; - } - return angle; - } - - public float getAnglesVariance() { - return mSumSquares / mCount + (mSum / mCount) * (mSum / mCount); - } - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java new file mode 100644 index 000000000000..99cc1a6d14fe --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class AnglesVarianceEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value > 0.05) evaluation++; + if (value > 0.10) evaluation++; + if (value > 0.20) evaluation++; + if (value > 0.40) evaluation++; + if (value > 0.80) evaluation++; + if (value > 1.50) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java index b76be1478bb4..89d20defc7db 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java @@ -20,7 +20,7 @@ import android.hardware.SensorEvent; import android.view.MotionEvent; /** - * An interface for classifiers for touch and sensor events. + * An abstract class for classifiers for touch and sensor events. */ public abstract class Classifier { public static final int QUICK_SETTINGS = 0; @@ -30,6 +30,7 @@ public abstract class Classifier { public static final int UNLOCK = 4; public static final int LEFT_AFFORDANCE = 5; public static final int RIGHT_AFFORDANCE = 6; + public static final int GENERIC = 7; /** * Contains all the information about touch events from which the classifier can query @@ -47,11 +48,4 @@ public abstract class Classifier { */ public void onSensorChanged(SensorEvent event) { } - - /** - * @param type the type of action for which this method is called - * @return a nonnegative value which is used to determine whether this a false touch. The - * bigger the value the greater the chance that this a false touch. - */ - public abstract float getFalseTouchEvaluation(int type); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java index 77b81d2b68fa..c83c74f69f90 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java @@ -19,32 +19,45 @@ package com.android.systemui.classifier; import android.util.SparseArray; import android.view.MotionEvent; +import java.util.ArrayList; + /** * Contains data which is used to classify interaction sequences on the lockscreen. It does, for * example, provide information on the current touch state. */ public class ClassifierData { private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>(); + private ArrayList<Stroke> mEndingStrokes = new ArrayList<>(); + private final float mDpi; - public ClassifierData() { + public ClassifierData(float dpi) { + mDpi = dpi; } public void update(MotionEvent event) { + mEndingStrokes.clear(); int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { mCurrentStrokes.clear(); } + for (int i = 0; i < event.getPointerCount(); i++) { int id = event.getPointerId(i); if (mCurrentStrokes.get(id) == null) { - mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano())); + mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano(), mDpi)); } mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i), event.getEventTimeNano()); + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL + || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { + mEndingStrokes.add(getStroke(id)); + } } } public void cleanUp(MotionEvent event) { + mEndingStrokes.clear(); int action = event.getActionMasked(); for (int i = 0; i < event.getPointerCount(); i++) { int id = event.getPointerId(i); @@ -56,6 +69,13 @@ public class ClassifierData { } /** + * @return the list of Strokes which are ending in the recently added MotionEvent + */ + public ArrayList<Stroke> getEndingStrokes() { + return mEndingStrokes; + } + + /** * @param id the id from MotionEvent * @return the Stroke assigned to the id */ diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java new file mode 100644 index 000000000000..299d0e3634b5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the general direction of a stroke and evaluates it depending on + * the type of action that takes place. + */ +public class DirectionClassifier extends StrokeClassifier { + public DirectionClassifier(ClassifierData classifierData) { + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + Point firstPoint = stroke.getPoints().get(0); + Point lastPoint = stroke.getPoints().get(stroke.getPoints().size() - 1); + return DirectionEvaluator.evaluate(lastPoint.x - firstPoint.x, lastPoint.y - firstPoint.y, + type); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java new file mode 100644 index 000000000000..e20b1ca64580 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.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.systemui.classifier; + +public class DirectionEvaluator { + public static float evaluate(float xDiff, float yDiff, int type) { + float falsingEvaluation = 5.5f; + boolean vertical = Math.abs(yDiff) >= Math.abs(xDiff); + switch (type) { + case Classifier.QUICK_SETTINGS: + case Classifier.NOTIFICATION_DRAG_DOWN: + if (!vertical || yDiff <= 0.0) { + return falsingEvaluation; + } + break; + case Classifier.NOTIFICATION_DISMISS: + if (vertical) { + return falsingEvaluation; + } + break; + case Classifier.UNLOCK: + if (!vertical || yDiff >= 0.0) { + return falsingEvaluation; + } + break; + case Classifier.LEFT_AFFORDANCE: + if (xDiff < 0.0 && yDiff > 0.0) { + return falsingEvaluation; + } + break; + case Classifier.RIGHT_AFFORDANCE: + if (xDiff > 0.0 && yDiff > 0.0) { + return falsingEvaluation; + } + default: + break; + } + return 0.0f; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java new file mode 100644 index 000000000000..8acb009a230f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.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.systemui.classifier; + +public class DistanceRatioEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value <= 1.0) evaluation++; + if (value <= 0.5) evaluation++; + if (value > 4.0) evaluation++; + if (value > 7.0) evaluation++; + if (value > 14.0) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java new file mode 100644 index 000000000000..892469428f4a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.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 com.android.systemui.classifier; + +/** + * A classifier which looks at the ratio between the duration of the stroke and its number of + * points. + */ +public class DurationCountClassifier extends StrokeClassifier { + public DurationCountClassifier(ClassifierData classifierData) { + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + return DurationCountEvaluator.evaluate(stroke.getDurationSeconds() / stroke.getCount()); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java new file mode 100644 index 000000000000..5395983968f7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + + +public class DurationCountEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 0.0105) evaluation++; + if (value < 0.00909) evaluation++; + if (value < 0.00667) evaluation++; + if (value > 0.0333) evaluation++; + if (value > 0.0500) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java new file mode 100644 index 000000000000..78bc0ddf1942 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the distance between the first and the last point from the stroke. + */ +public class EndPointLengthClassifier extends StrokeClassifier { + public EndPointLengthClassifier(ClassifierData classifierData) { + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + return EndPointLengthEvaluator.evaluate(stroke.getEndPointLength()); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java new file mode 100644 index 000000000000..bb2f1c4e355d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class EndPointLengthEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 0.05) evaluation += 2.0; + if (value < 0.1) evaluation += 2.0; + if (value < 0.2) evaluation += 2.0; + if (value < 0.3) evaluation += 2.0; + if (value < 0.4) evaluation += 2.0; + if (value < 0.5) evaluation += 2.0; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java new file mode 100644 index 000000000000..c125e0093db5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the ratio between the total length covered by the stroke and the + * distance between the first and last point from this stroke. + */ +public class EndPointRatioClassifier extends StrokeClassifier { + public EndPointRatioClassifier(ClassifierData classifierData) { + mClassifierData = classifierData; + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + if (stroke.getTotalLength() == 0.0f) { + return 1.0f; + } + return EndPointRatioEvaluator.evaluate( + stroke.getEndPointLength() / stroke.getTotalLength()); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java new file mode 100644 index 000000000000..529fcec2710e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class EndPointRatioEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 0.85) evaluation++; + if (value < 0.75) evaluation++; + if (value < 0.65) evaluation++; + if (value < 0.55) evaluation++; + if (value < 0.45) evaluation++; + if (value < 0.35) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java index 347273ac0f68..735a7c4bad4a 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java @@ -39,7 +39,11 @@ import com.android.systemui.statusbar.StatusBarState; public class FalsingManager implements SensorEventListener { private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer"; - private static final int[] SENSORS = new int[] { + private static final int[] CLASSIFIER_SENSORS = new int[] { + Sensor.TYPE_PROXIMITY, + }; + + private static final int[] COLLECTOR_SENSORS = new int[] { Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_GYROSCOPE, Sensor.TYPE_PROXIMITY, @@ -113,7 +117,17 @@ public class FalsingManager implements SensorEventListener { private void onSessionStart() { mBouncerOn = false; mSessionActive = true; - for (int sensorType : SENSORS) { + + if (mHumanInteractionClassifier.isEnabled()) { + registerSensors(CLASSIFIER_SENSORS); + } + if (mDataCollector.isEnabled()) { + registerSensors(COLLECTOR_SENSORS); + } + } + + private void registerSensors(int [] sensors) { + for (int sensorType : sensors) { Sensor s = mSensorManager.getDefaultSensor(sensorType); if (s != null) { mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME); @@ -121,16 +135,19 @@ public class FalsingManager implements SensorEventListener { } } + public boolean isClassiferEnabled() { + return mHumanInteractionClassifier.isEnabled(); + } + private boolean isEnabled() { return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled(); } /** - * @param type the type of action for which this method is called * @return true if the classifier determined that this is not a human interacting with the phone */ - public boolean isFalseTouch(int type) { - return mHumanInteractionClassifier.getFalseTouchEvaluation(type) > 0.5; + public boolean isFalseTouch() { + return mHumanInteractionClassifier.isFalseTouch(); } @Override @@ -189,6 +206,7 @@ public class FalsingManager implements SensorEventListener { } public void onQsDown() { + mHumanInteractionClassifier.setType(Classifier.QUICK_SETTINGS); mDataCollector.onQsDown(); } @@ -197,6 +215,7 @@ public class FalsingManager implements SensorEventListener { } public void onTrackingStarted() { + mHumanInteractionClassifier.setType(Classifier.UNLOCK); mDataCollector.onTrackingStarted(); } @@ -217,6 +236,7 @@ public class FalsingManager implements SensorEventListener { } public void onNotificatonStartDraggingDown() { + mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DRAG_DOWN); mDataCollector.onNotificatonStartDraggingDown(); } @@ -229,6 +249,7 @@ public class FalsingManager implements SensorEventListener { } public void onNotificatonStartDismissing() { + mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DISMISS); mDataCollector.onNotificatonStartDismissing(); } @@ -245,6 +266,11 @@ public class FalsingManager implements SensorEventListener { } public void onAffordanceSwipingStarted(boolean rightCorner) { + if (rightCorner) { + mHumanInteractionClassifier.setType(Classifier.RIGHT_AFFORDANCE); + } else { + mHumanInteractionClassifier.setType(Classifier.LEFT_AFFORDANCE); + } mDataCollector.onAffordanceSwipingStarted(rightCorner); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java new file mode 100644 index 000000000000..11388fc49594 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * An abstract class for classifiers which classify the whole gesture (all the strokes which + * occurred from DOWN event to UP/CANCEL event) + */ +public abstract class GestureClassifier extends Classifier { + + /** + * @param type the type of action for which this method is called + * @return a non-negative value which is used to determine whether the most recent gesture is a + * false interaction; the bigger the value the greater the chance that this a false + * interaction. + */ + public abstract float getFalseTouchEvaluation(int type); +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java new file mode 100644 index 000000000000..85a9bee8d977 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.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 com.android.systemui.classifier; + +import java.util.ArrayList; + +/** + * Holds the evaluations for ended strokes and gestures. These values are decreased through time. + */ +public class HistoryEvaluator { + private static final float INTERVAL = 50.0f; + private static final float HISTORY_FACTOR = 0.9f; + private static final float EPSILON = 1e-5f; + + private final ArrayList<Data> mStrokes = new ArrayList<>(); + private final ArrayList<Data> mGestureWeights = new ArrayList<>(); + private long mLastUpdate; + + public HistoryEvaluator() { + mLastUpdate = System.currentTimeMillis(); + } + + public void addStroke(float evaluation) { + decayValue(); + mStrokes.add(new Data(evaluation)); + } + + public void addGesture(float evaluation) { + decayValue(); + mGestureWeights.add(new Data(evaluation)); + } + + /** + * Calculates the weighted average of strokes and adds to it the weighted average of gestures + */ + public float getEvaluation() { + return weightedAverage(mStrokes) + weightedAverage(mGestureWeights); + } + + private float weightedAverage(ArrayList<Data> list) { + float sumValue = 0.0f; + float sumWeight = 0.0f; + int size = list.size(); + for (int i = 0; i < size; i++) { + Data data = list.get(i); + sumValue += data.evaluation * data.weight; + sumWeight += data.weight; + } + + if (sumWeight == 0.0f) { + return 0.0f; + } + + return sumValue / sumWeight; + } + + private void decayValue() { + long currentTimeMillis = System.currentTimeMillis(); + + // All weights are multiplied by HISTORY_FACTOR after each INTERVAL milliseconds. + float factor = (float) Math.pow(HISTORY_FACTOR, + (float) (currentTimeMillis - mLastUpdate) / INTERVAL); + + decayValue(mStrokes, factor); + decayValue(mGestureWeights, factor); + mLastUpdate = currentTimeMillis; + } + + private void decayValue(ArrayList<Data> list, float factor) { + int size = list.size(); + for (int i = 0; i < size; i++) { + list.get(i).weight *= factor; + } + + // Removing evaluations with such small weights that they do not matter anymore + while (!list.isEmpty() && isZero(list.get(0).weight)) { + list.remove(0); + } + } + + private boolean isZero(float x) { + return x <= EPSILON && x >= -EPSILON; + } + + /** + * For each stroke it holds its initial value and the current weight. Initially the + * weight is set to 1.0 + */ + private static class Data { + public float evaluation; + public float weight; + + public Data(float evaluation) { + this.evaluation = evaluation; + weight = 1.0f; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java index a5f6df858d2c..a7a569419624 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java @@ -23,20 +23,33 @@ import android.os.Build; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; +import android.util.DisplayMetrics; import android.view.MotionEvent; +import java.util.ArrayDeque; +import java.util.ArrayList; + /** * An classifier trying to determine whether it is a human interacting with the phone or not. */ public class HumanInteractionClassifier extends Classifier { private static final String HIC_ENABLE = "HIC_enable"; + private static final float FINGER_DISTANCE = 0.1f; private static HumanInteractionClassifier sInstance = null; private final Handler mHandler = new Handler(); private final Context mContext; - private AnglesVarianceClassifier mAnglesVarianceClassifier; - private boolean mEnableClassifier = false; + private ArrayList<StrokeClassifier> mStrokeClassifiers = new ArrayList<>(); + private ArrayList<GestureClassifier> mGestureClassifiers = new ArrayList<>(); + private ArrayDeque<MotionEvent> mBufferedEvents = new ArrayDeque<>(); + private final int mStrokeClassifiersSize; + private final int mGestureClassifiersSize; + private final float mDpi; + + private HistoryEvaluator mHistoryEvaluator; + private boolean mEnableClassifier = true; + private int mCurrentType = Classifier.GENERIC; protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { @Override @@ -47,8 +60,30 @@ public class HumanInteractionClassifier extends Classifier { private HumanInteractionClassifier(Context context) { mContext = context; - mClassifierData = new ClassifierData(); - mAnglesVarianceClassifier = new AnglesVarianceClassifier(mClassifierData); + DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); + + // If the phone is rotated to landscape, the calculations would be wrong if xdpi and ydpi + // were to be used separately. Due negligible differences in xdpi and ydpi we can just + // take the average. + mDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2.0f; + mClassifierData = new ClassifierData(mDpi); + mHistoryEvaluator = new HistoryEvaluator(); + + mStrokeClassifiers.add(new AnglesClassifier(mClassifierData)); + mStrokeClassifiers.add(new SpeedClassifier(mClassifierData)); + mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData)); + mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData)); + mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData)); + mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData)); + mStrokeClassifiers.add(new SpeedAnglesClassifier(mClassifierData)); + mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData)); + mStrokeClassifiers.add(new DirectionClassifier(mClassifierData)); + + mGestureClassifiers.add(new PointerCountClassifier(mClassifierData)); + mGestureClassifiers.add(new ProximityClassifier(mClassifierData)); + + mStrokeClassifiersSize = mStrokeClassifiers.size(); + mGestureClassifiersSize = mGestureClassifiers.size(); mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(HIC_ENABLE), false, @@ -71,25 +106,95 @@ public class HumanInteractionClassifier extends Classifier { HIC_ENABLE, 0); } + public void setType(int type) { + mCurrentType = type; + } + @Override public void onTouchEvent(MotionEvent event) { - if (mEnableClassifier) { - mClassifierData.update(event); - mAnglesVarianceClassifier.onTouchEvent(event); - mClassifierData.cleanUp(event); + if (!mEnableClassifier) { + return; + } + + // If the user is dragging down the notification, he might want to drag it down + // enough to see the content, read it for a while and then lift the finger to open + // the notification. This kind of motion scores very bad in the Classifier so the + // MotionEvents which are close to the current position of the finger are not + // sent to the classifiers until the finger moves far enough. When the finger if lifted + // up, the last MotionEvent which was far enough from the finger is set as the final + // MotionEvent and sent to the Classifiers. + if (mCurrentType == Classifier.NOTIFICATION_DRAG_DOWN) { + mBufferedEvents.add(MotionEvent.obtain(event)); + Point pointEnd = new Point(event.getX() / mDpi, event.getY() / mDpi); + + while (pointEnd.dist(new Point(mBufferedEvents.getFirst().getX() / mDpi, + mBufferedEvents.getFirst().getY() / mDpi)) > FINGER_DISTANCE) { + addTouchEvent(mBufferedEvents.getFirst()); + mBufferedEvents.remove(); + } + + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_UP) { + mBufferedEvents.getFirst().setAction(MotionEvent.ACTION_UP); + addTouchEvent(mBufferedEvents.getFirst()); + mBufferedEvents.clear(); + } + } else { + addTouchEvent(event); + } + } + + private void addTouchEvent(MotionEvent event) { + mClassifierData.update(event); + + for (int i = 0; i < mStrokeClassifiersSize; i++) { + mStrokeClassifiers.get(i).onTouchEvent(event); + } + + for (int i = 0; i < mGestureClassifiersSize; i++) { + mGestureClassifiers.get(i).onTouchEvent(event); + } + + int size = mClassifierData.getEndingStrokes().size(); + for (int i = 0; i < size; i++) { + Stroke stroke = mClassifierData.getEndingStrokes().get(i); + float evaluation = 0.0f; + for (int j = 0; j < mStrokeClassifiersSize; j++) { + evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation( + mCurrentType, stroke); + } + mHistoryEvaluator.addStroke(evaluation); } + + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + float evaluation = 0.0f; + for (int i = 0; i < mGestureClassifiersSize; i++) { + evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType); + } + mHistoryEvaluator.addGesture(evaluation); + setType(Classifier.GENERIC); + } + + mClassifierData.cleanUp(event); } @Override public void onSensorChanged(SensorEvent event) { + for (int i = 0; i < mStrokeClassifiers.size(); i++) { + mStrokeClassifiers.get(i).onSensorChanged(event); + } + + for (int i = 0; i < mGestureClassifiers.size(); i++) { + mGestureClassifiers.get(i).onSensorChanged(event); + } } - @Override - public float getFalseTouchEvaluation(int type) { + public boolean isFalseTouch() { if (mEnableClassifier) { - return mAnglesVarianceClassifier.getFalseTouchEvaluation(type); + return mHistoryEvaluator.getEvaluation() >= 5.0f; } - return 0.0f; + return false; } public boolean isEnabled() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java new file mode 100644 index 000000000000..cedf4676beec --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the ratio between the length of the stroke and its number of + * points. The number of points is subtracted by 2 because the UP event comes in with some delay + * and it should not influence the ratio and also strokes which are long and have a small number + * of points are punished more (these kind of strokes are usually bad ones and they tend to score + * well in other classifiers). + */ +public class LengthCountClassifier extends StrokeClassifier { + public LengthCountClassifier(ClassifierData classifierData) { + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + return LengthCountEvaluator.evaluate(stroke.getTotalLength() + / Math.max(1.0f, stroke.getCount() - 2)); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java new file mode 100644 index 000000000000..dac7a6f720a7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier which looks at the ratio between the length of the stroke and its number of + * points. + */ +public class LengthCountEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 0.09) evaluation++; + if (value < 0.05) evaluation++; + if (value < 0.02) evaluation++; + if (value > 0.6) evaluation++; + if (value > 0.9) evaluation++; + if (value > 1.2) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Point.java b/packages/SystemUI/src/com/android/systemui/classifier/Point.java index e7dbae19eb31..f3dc2be4144b 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/Point.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/Point.java @@ -56,4 +56,28 @@ public class Point { public float dotProduct(Point a, Point b) { return (a.x - x) * (b.x - x) + (a.y - y) * (b.y - y); } + + /** + * Calculates the angle in radians created by points (a, this, b). If any two of these points + * are the same, the method will return 0.0f + * + * @return the angle in radians + */ + public float getAngle(Point a, Point b) { + float dist1 = dist(a); + float dist2 = dist(b); + + if (dist1 == 0.0f || dist2 == 0.0f) { + return 0.0f; + } + + float crossProduct = crossProduct(a, b); + float dotProduct = dotProduct(a, b); + float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2)); + float angle = (float) Math.acos(cos); + if (crossProduct < 0.0) { + angle = 2.0f * (float) Math.PI - angle; + } + return angle; + } } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java new file mode 100644 index 000000000000..5097b635807e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.view.MotionEvent; + +/** + * A classifier which looks at the total number of traces in the whole gesture. + */ +public class PointerCountClassifier extends GestureClassifier { + private int mCount; + + public PointerCountClassifier(ClassifierData classifierData) { + mCount = 0; + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mCount = 1; + } + + if (action == MotionEvent.ACTION_POINTER_DOWN) { + ++mCount; + } + } + + @Override + public float getFalseTouchEvaluation(int type) { + return PointerCountEvaluator.evaluate(mCount); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java new file mode 100644 index 000000000000..d7a3af0360af --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class PointerCountEvaluator { + public static float evaluate(int value) { + return (value - 1) * (value - 1); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java new file mode 100644 index 000000000000..69950640337f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.view.MotionEvent; + +/** + * A classifier which looks at the proximity sensor during the gesture. It calculates the percentage + * the proximity sensor showing the near state during the whole gesture + */ +public class ProximityClassifier extends GestureClassifier { + private long mGestureStartTimeNano; + private long mNearStartTimeNano; + private long mNearDuration; + private boolean mNear; + private float mAverageNear; + + public ProximityClassifier(ClassifierData classifierData) { + } + + @Override + public void onSensorChanged(SensorEvent event) { + if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) { + update(event.values[0] < event.sensor.getMaximumRange(), event.timestamp); + } + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mGestureStartTimeNano = event.getEventTimeNano(); + mNearStartTimeNano = event.getEventTimeNano(); + mNearDuration = 0; + } + + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + update(mNear, event.getEventTimeNano()); + long duration = event.getEventTimeNano() - mGestureStartTimeNano; + + if (duration == 0) { + mAverageNear = mNear ? 1.0f : 0.0f; + } else { + mAverageNear = (float) mNearDuration / (float) duration; + } + } + } + + + /** + * @param near is the sensor showing the near state right now + * @param timestampNano time of this event in nanoseconds + */ + private void update(boolean near, long timestampNano) { + // This if is necessary because MotionEvents and SensorEvents do not come in + // chronological order + if (timestampNano > mNearStartTimeNano) { + // if the state before was near then add the difference of the current time and + // mNearStartTimeNano to mNearDuration. + if (mNear) { + mNearDuration += timestampNano - mNearStartTimeNano; + } + + // if the new state is near, set mNearStartTimeNano equal to this moment. + if (near) { + mNearStartTimeNano = timestampNano; + } + } + mNear = near; + } + + @Override + public float getFalseTouchEvaluation(int type) { + return ProximityEvaluator.evaluate(mAverageNear, type); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java new file mode 100644 index 000000000000..91002bf1291c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.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.systemui.classifier; + +public class ProximityEvaluator { + public static float evaluate(float value, int type) { + float evaluation = 0.0f; + float threshold = 0.1f; + if (type == Classifier.QUICK_SETTINGS) { + threshold = 1.0f; + } + if (value >= threshold) evaluation += 2.0; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java new file mode 100644 index 000000000000..d544a3d68671 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +import android.view.MotionEvent; + +import java.lang.Math; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * A classifier which for each point from a stroke, it creates a point on plane with coordinates + * (timeOffsetNano, distanceCoveredUpToThisPoint) (scaled by DURATION_SCALE and LENGTH_SCALE) + * and then it calculates the angle variance of these points like the class + * {@link AnglesClassifier} (without splitting it into two parts). The classifier ignores + * the last point of a stroke because the UP event comes in with some delay and this ruins the + * smoothness of this curve. Additionally, the classifier classifies calculates the percentage of + * angles which value is in [PI - ANGLE_DEVIATION, 2* PI) interval. The reason why the classifier + * does that is because the speed of a good stroke is most often increases, so most of these angels + * should be in this interval. + */ +public class SpeedAnglesClassifier extends StrokeClassifier { + private HashMap<Stroke, Data> mStrokeMap = new HashMap<>(); + + public SpeedAnglesClassifier(ClassifierData classifierData) { + mClassifierData = classifierData; + } + + @Override + public void onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + if (action == MotionEvent.ACTION_DOWN) { + mStrokeMap.clear(); + } + + for (int i = 0; i < event.getPointerCount(); i++) { + Stroke stroke = mClassifierData.getStroke(event.getPointerId(i)); + + if (mStrokeMap.get(stroke) == null) { + mStrokeMap.put(stroke, new Data()); + } + + if (action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL + && !(action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) { + mStrokeMap.get(stroke).addPoint( + stroke.getPoints().get(stroke.getPoints().size() - 1)); + } + } + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + Data data = mStrokeMap.get(stroke); + return SpeedVarianceEvaluator.evaluate(data.getAnglesVariance()) + + SpeedAnglesPercentageEvaluator.evaluate(data.getAnglesPercentage()); + } + + private static class Data { + private final float DURATION_SCALE = 1e8f; + private final float LENGTH_SCALE = 1.0f; + private final float ANGLE_DEVIATION = (float) Math.PI / 10.0f; + + private List<Point> mLastThreePoints = new ArrayList<>(); + private Point mPreviousPoint; + private float mPreviousAngle; + private float mSumSquares; + private float mSum; + private float mCount; + private float mDist; + private float mAnglesCount; + private float mAcceleratingAngles; + + public Data() { + mPreviousPoint = null; + mPreviousAngle = (float) Math.PI; + mSumSquares = 0.0f; + mSum = 0.0f; + mCount = 1.0f; + mDist = 0.0f; + mAnglesCount = mAcceleratingAngles = 0.0f; + } + + public void addPoint(Point point) { + if (mPreviousPoint != null) { + mDist += mPreviousPoint.dist(point); + } + + mPreviousPoint = point; + Point speedPoint = new Point((float) point.timeOffsetNano / DURATION_SCALE, + mDist / LENGTH_SCALE); + + // Checking if the added point is different than the previously added point + // Repetitions are being ignored so that proper angles are calculated. + if (mLastThreePoints.isEmpty() + || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(speedPoint)) { + mLastThreePoints.add(speedPoint); + if (mLastThreePoints.size() == 4) { + mLastThreePoints.remove(0); + + float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0), + mLastThreePoints.get(2)); + + mAnglesCount++; + if (angle >= (float) Math.PI - ANGLE_DEVIATION) { + mAcceleratingAngles++; + } + + float difference = angle - mPreviousAngle; + mSum += difference; + mSumSquares += difference * difference; + mCount += 1.0; + mPreviousAngle = angle; + } + } + } + + public float getAnglesVariance() { + return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount); + } + + public float getAnglesPercentage() { + if (mAnglesCount == 0.0f) { + return 1.0f; + } + return (mAcceleratingAngles) / mAnglesCount; + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java new file mode 100644 index 000000000000..2a45fa36dbc6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class SpeedAnglesPercentageEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 1.00) evaluation++; + if (value < 0.95) evaluation++; + if (value < 0.90) evaluation++; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java new file mode 100644 index 000000000000..81b78c7ecdfe --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +/** + * A classifier that looks at the speed of the stroke. It calculates the speed of a stroke in + * inches per second. + */ +public class SpeedClassifier extends StrokeClassifier { + private final float NANOS_TO_SECONDS = 1e9f; + + public SpeedClassifier(ClassifierData classifierData) { + } + + @Override + public float getFalseTouchEvaluation(int type, Stroke stroke) { + float duration = (float) stroke.getDurationNanos() / NANOS_TO_SECONDS; + if (duration == 0.0f) { + return SpeedEvaluator.evaluate(0.0f); + } + return SpeedEvaluator.evaluate(stroke.getTotalLength() / duration); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java new file mode 100644 index 000000000000..c0e4a2ddc89a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.classifier; + +public class SpeedEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value < 4.0 || value > 35.0) evaluation += 1.0; + if (value < 2.2) evaluation += 1.0; + if (value > 50.0) evaluation += 1.0; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java new file mode 100644 index 000000000000..349aa9ed49d6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java @@ -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 com.android.systemui.classifier; + +public class SpeedRatioEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value > 9.0) ++evaluation; + if (value > 18.0) ++evaluation; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java new file mode 100644 index 000000000000..8f9a7e159638 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.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 com.android.systemui.classifier; + +public class SpeedVarianceEvaluator { + public static float evaluate(float value) { + float evaluation = 0.0f; + if (value > 0.06) evaluation += 1.0; + if (value > 0.15) evaluation += 1.0; + if (value > 0.3) evaluation += 1.0; + if (value > 0.6) evaluation += 1.0; + return evaluation; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java index f386cbe458e6..fb04d3e73a2d 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java @@ -19,20 +19,50 @@ package com.android.systemui.classifier; import java.util.ArrayList; /** - * Contains data about movement traces (pointers) + * Contains data about a stroke (a single trace, all the events from a given id from the + * DOWN/POINTER_DOWN event till the UP/POINTER_UP/CANCEL event.) */ public class Stroke { + private final float NANOS_TO_SECONDS = 1e9f; + private ArrayList<Point> mPoints = new ArrayList<>(); private long mStartTimeNano; private long mEndTimeNano; + private float mLength; + private final float mDpi; - public Stroke(long eventTimeNano) { + public Stroke(long eventTimeNano, float dpi) { + mDpi = dpi; mStartTimeNano = mEndTimeNano = eventTimeNano; } public void addPoint(float x, float y, long eventTimeNano) { mEndTimeNano = eventTimeNano; - mPoints.add(new Point(x, y, eventTimeNano - mStartTimeNano)); + Point point = new Point(x / mDpi, y / mDpi, eventTimeNano - mStartTimeNano); + if (!mPoints.isEmpty()) { + mLength += mPoints.get(mPoints.size() - 1).dist(point); + } + mPoints.add(point); + } + + public int getCount() { + return mPoints.size(); + } + + public float getTotalLength() { + return mLength; + } + + public float getEndPointLength() { + return mPoints.get(0).dist(mPoints.get(mPoints.size() - 1)); + } + + public long getDurationNanos() { + return mEndTimeNano - mStartTimeNano; + } + + public float getDurationSeconds() { + return (float) getDurationNanos() / NANOS_TO_SECONDS; } public ArrayList<Point> getPoints() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java new file mode 100644 index 000000000000..5da392f31d63 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.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 com.android.systemui.classifier; + +/** + * An abstract class for classifiers which classify each stroke separately. + */ +public abstract class StrokeClassifier extends Classifier { + + /** + * @param type the type of action for which this method is called + * @param stroke the stroke for which the evaluation will be calculated + * @return a non-negative value which is used to determine whether this a false touch; the + * bigger the value the greater the chance that this a false touch + */ + public abstract float getFalseTouchEvaluation(int type, Stroke stroke); +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 3b3593b4c477..e562682551e4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -30,16 +30,7 @@ import android.view.View; import android.view.ViewGroup; import com.android.systemui.qs.QSTile.State; -import com.android.systemui.statusbar.policy.BluetoothController; -import com.android.systemui.statusbar.policy.CastController; -import com.android.systemui.statusbar.policy.FlashlightController; -import com.android.systemui.statusbar.policy.HotspotController; -import com.android.systemui.statusbar.policy.KeyguardMonitor; -import com.android.systemui.statusbar.policy.Listenable; -import com.android.systemui.statusbar.policy.LocationController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RotationLockController; -import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.statusbar.policy.*; import java.util.Collection; import java.util.Objects; @@ -349,6 +340,9 @@ public abstract class QSTile<TState extends State> implements Listenable { CastController getCastController(); FlashlightController getFlashlightController(); KeyguardMonitor getKeyguardMonitor(); + UserSwitcherController getUserSwitcherController(); + UserInfoController getUserInfoController(); + BatteryController getBatteryController(); public interface Callback { void onTilesChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java index 08cdc1eee65c..e575923fdd09 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java @@ -267,7 +267,7 @@ public class QSTileView extends ViewGroup { final int w = MeasureSpec.getSize(widthMeasureSpec); final int h = MeasureSpec.getSize(heightMeasureSpec); final int iconSpec = exactly(mIconSizePx); - mIcon.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.AT_MOST), iconSpec); + mIcon.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), iconSpec); switch (mType) { case QS_TYPE_QUICK: mCircle.measure( diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java index 84b05d0055ea..f676ea3499cb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java @@ -44,7 +44,8 @@ public class CustomQSTileHost extends QSTileHost { host.getRotationLockController(), host.getNetworkController(), host.getZenModeController(), host.getHotspotController(), host.getCastController(), host.getFlashlightController(), host.getUserSwitcherController(), - host.getKeyguardMonitor(), new BlankSecurityController()); + host.getUserInfoController(), host.getKeyguardMonitor(), + new BlankSecurityController(), host.getBatteryController()); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java new file mode 100644 index 000000000000..8f9655d65d15 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.qs.tiles; + +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import com.android.internal.logging.MetricsLogger; +import com.android.systemui.BatteryMeterDrawable; +import com.android.systemui.R; +import com.android.systemui.qs.QSTile; +import com.android.systemui.statusbar.policy.BatteryController; + +import java.text.NumberFormat; + +public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback { + + private final BatteryMeterDrawable mDrawable; + private final BatteryController mBatteryController; + + private int mLevel; + + public BatteryTile(Host host) { + super(host); + mBatteryController = host.getBatteryController(); + mDrawable = new BatteryMeterDrawable(host.getContext(), new Handler(), + host.getContext().getColor(R.color.batterymeter_frame_color)); + mDrawable.setBatteryController(mBatteryController); + } + + @Override + protected State newTileState() { + return new QSTile.State(); + } + + @Override + public int getMetricsCategory() { + return MetricsLogger.QS_BATTERY_TILE; + } + + @Override + public void setListening(boolean listening) { + if (listening) { + mDrawable.startListening(); + mBatteryController.addStateChangedCallback(this); + } else { + mDrawable.stopListening(); + mBatteryController.removeStateChangedCallback(this); + } + } + + @Override + protected void handleClick() { + mHost.startActivityDismissingKeyguard(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY)); + } + + @Override + protected void handleUpdateState(State state, Object arg) { + int level = (arg != null) ? (Integer) arg : mLevel; + String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0); + + state.visible = true; + state.icon = new Icon() { + @Override + public Drawable getDrawable(Context context) { + return mDrawable; + } + }; + state.label = percentage; + } + + @Override + public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { + mLevel = level; + refreshState((Integer) level); + } + + @Override + public void onPowerSaveChanged() { + + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java new file mode 100644 index 000000000000..3675f02b9dee --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.qs.tiles; + +import com.android.internal.logging.MetricsLogger; +import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.QSTileView; +import com.android.systemui.statusbar.policy.KeyguardMonitor; +import com.android.systemui.R; + +public class QLockTile extends QSTile<QSTile.State> implements KeyguardMonitor.Callback { + + private final KeyguardMonitor mKeyguard; + + public QLockTile(Host host) { + super(host); + mKeyguard = host.getKeyguardMonitor(); + } + + @Override + public int getTileType() { + return QSTileView.QS_TYPE_QUICK; + } + + @Override + protected State newTileState() { + return new State(); + } + + @Override + public void setListening(boolean listening) { + if (listening) { + mKeyguard.addCallback(this); + } else { + mKeyguard.removeCallback(this); + } + } + + @Override + public int getMetricsCategory() { + return MetricsLogger.QS_LOCK_TILE; + } + + @Override + public void onKeyguardChanged() { + refreshState(); + } + + @Override + protected void handleClick() { + if (mKeyguard.isShowing()) { + mKeyguard.unlock(); + } else { + mKeyguard.lock(); + } + } + + @Override + protected void handleUpdateState(State state, Object arg) { + // TOD: Content description. + state.visible = true; + if (mKeyguard.isShowing()) { + state.icon = ResourceIcon.get(R.drawable.ic_qs_lock); + } else { + state.icon = ResourceIcon.get(R.drawable.ic_qs_lock_open); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java new file mode 100644 index 000000000000..3c5ab8d491b7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.qs.tiles; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.Pair; +import com.android.internal.logging.MetricsLogger; +import com.android.systemui.qs.QSTile; +import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.statusbar.policy.UserSwitcherController; + +public class UserTile extends QSTile<QSTile.State> implements UserInfoController.OnUserInfoChangedListener { + + private final UserSwitcherController mUserSwitcherController; + private final UserInfoController mUserInfoController; + private Pair<String, Drawable> mLastUpdate; + + public UserTile(Host host) { + super(host); + mUserSwitcherController = host.getUserSwitcherController(); + mUserInfoController = host.getUserInfoController(); + } + + @Override + protected State newTileState() { + return new QSTile.State(); + } + + @Override + protected void handleClick() { + showDetail(true); + } + + @Override + public DetailAdapter getDetailAdapter() { + return mUserSwitcherController.userDetailAdapter; + } + + @Override + public int getMetricsCategory() { + return MetricsLogger.QS_USER_TILE; + } + + @Override + public void setListening(boolean listening) { + if (listening) { + mUserInfoController.addListener(this); + } else { + mUserInfoController.remListener(this); + } + } + + @Override + protected void handleUpdateState(State state, Object arg) { + final Pair<String, Drawable> p = arg != null ? (Pair<String, Drawable>) arg : mLastUpdate; + state.visible = p != null; + if (!state.visible) return; + state.label = p.first; + // TODO: Better content description. + state.contentDescription = p.first; + state.icon = new Icon() { + @Override + public Drawable getDrawable(Context context) { + return p.second; + } + }; + } + + @Override + public void onUserInfoChanged(String name, Drawable picture) { + mLastUpdate = new Pair<>(name, picture); + refreshState(mLastUpdate); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index e1a88152a1fd..978166438303 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -29,8 +29,6 @@ public class Constants { } public static class DebugFlags { - // Enable this with any other debug flag to see more info - public static final boolean Verbose = false; public static class App { // Enables debug drawing for the transition thumbnail @@ -39,10 +37,6 @@ public class Constants { public static final boolean EnableTaskFiltering = false; // Enables dismiss-all public static final boolean EnableDismissAll = false; - // Enables debug mode - public static final boolean EnableDebugMode = false; - // Enables the search bar layout - public static final boolean EnableSearchLayout = true; // Enables the thumbnail alpha on the front-most task public static final boolean EnableThumbnailAlphaOnFrontmost = false; // This disables the bitmap and icon caches @@ -63,7 +57,6 @@ public class Constants { public static class Values { public static class App { public static int AppWidgetHostId = 1024; - public static String DebugModeVersion = "A"; } public static class TaskStackView { diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index cbccaf887d69..23cc8f067d83 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -38,7 +38,6 @@ import android.util.MutableBoolean; import android.view.Display; import android.view.LayoutInflater; import android.view.View; - import com.android.internal.logging.MetricsLogger; import com.android.systemui.Prefs; import com.android.systemui.R; @@ -164,7 +163,6 @@ public class Recents extends SystemUI static RecentsTaskLoadPlan sInstanceLoadPlan; static Recents sInstance; - LayoutInflater mInflater; SystemServicesProxy mSystemServicesProxy; Handler mHandler; TaskStackListenerImpl mTaskStackListener; @@ -176,12 +174,14 @@ public class Recents extends SystemUI // Task launching RecentsConfiguration mConfig; + Rect mSearchBarBounds = new Rect(); Rect mTaskStackBounds = new Rect(); - Rect mSystemInsets = new Rect(); + Rect mLastTaskViewBounds = new Rect(); TaskViewTransform mTmpTransform = new TaskViewTransform(); int mStatusBarHeight; int mNavBarHeight; int mNavBarWidth; + int mTaskBarHeight; // Header (for transition) TaskViewHeader mHeaderBar; @@ -229,11 +229,11 @@ public class Recents extends SystemUI if (sInstance == null) { sInstance = this; } + Resources res = mContext.getResources(); RecentsTaskLoader.initialize(mContext); - mInflater = LayoutInflater.from(mContext); + LayoutInflater inflater = LayoutInflater.from(mContext); mSystemServicesProxy = new SystemServicesProxy(mContext); mHandler = new Handler(); - mTaskStackBounds = new Rect(); mAppWidgetHost = new RecentsAppWidgetHost(mContext, Constants.Values.App.AppWidgetHostId); // Register the task stack listener @@ -241,7 +241,7 @@ public class Recents extends SystemUI mSystemServicesProxy.registerTaskStackListener(mTaskStackListener); // Only the owner has the callback to update the SysUI visibility flags, so all non-owner - // instances of AlternateRecentsComponent needs to notify the owner when the visibility + // instances of RecentsComponent needs to notify the owner when the visibility // changes. if (mSystemServicesProxy.isForegroundUserSystem()) { mProxyBroadcastReceiver = new RecentsOwnerEventProxyReceiver(); @@ -254,8 +254,16 @@ public class Recents extends SystemUI // Initialize some static datastructures TaskStackViewLayoutAlgorithm.initializeCurve(); - // Load the header bar layout - reloadHeaderBarLayout(); + // Initialize the static configuration resources + mConfig = RecentsConfiguration.initialize(mContext, mSystemServicesProxy); + mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); + mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height); + mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width); + mTaskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height); + mDummyStackView = new TaskStackView(mContext, new TaskStack()); + mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header, + null, false); + reloadHeaderBarLayout(true /* tryAndBindSearchWidget */); // When we start, preload the data associated with the previous recent tasks. // We can use a new plan since the caches will be the same. @@ -273,6 +281,7 @@ public class Recents extends SystemUI @Override public void onBootCompleted() { mBootCompleted = true; + reloadHeaderBarLayout(true /* tryAndBindSearchWidget */); } /** Shows the Recents. */ @@ -293,7 +302,7 @@ public class Recents extends SystemUI mTriggeredFromAltTab = triggeredFromAltTab; try { - startRecentsActivity(); + showRecentsActivity(); } catch (ActivityNotFoundException e) { Console.logRawError("Failed to launch RecentAppsIntent", e); } @@ -488,54 +497,52 @@ public class Recents extends SystemUI void configurationChanged() { // Don't reuse task stack views if the configuration changes mCanReuseTaskStackViews = false; - // Reload the header bar layout - reloadHeaderBarLayout(); + mConfig.updateOnConfigurationChange(); } - /** Prepares the header bar layout. */ - void reloadHeaderBarLayout() { - Resources res = mContext.getResources(); + /** + * Prepares the header bar layout for the next transition, if the task view bounds has changed + * since the last call, it will attempt to re-measure and layout the header bar to the new size. + * + * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one + * is not already bound (can be expensive) + */ + void reloadHeaderBarLayout(boolean tryAndBindSearchWidget) { Rect windowRect = mSystemServicesProxy.getWindowRect(); - mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); - mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height); - mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width); - mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy); - mConfig.updateOnConfigurationChange(); - Rect searchBarBounds = new Rect(); - // Try and pre-emptively bind the search widget on startup to ensure that we - // have the right thumbnail bounds to animate to. - // Note: We have to reload the widget id before we get the task stack bounds below - if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) { - mConfig.getSearchBarBounds(windowRect, - mStatusBarHeight, searchBarBounds); + // Update the configuration for the current state + mConfig.update(mContext, mSystemServicesProxy, mSystemServicesProxy.getWindowRect()); + + if (tryAndBindSearchWidget) { + // Try and pre-emptively bind the search widget on startup to ensure that we + // have the right thumbnail bounds to animate to. + // Note: We have to reload the widget id before we get the task stack bounds below + if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) { + mConfig.getSearchBarBounds(windowRect, + mStatusBarHeight, mSearchBarBounds); + } } mConfig.getAvailableTaskStackBounds(windowRect, - mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), searchBarBounds, - mTaskStackBounds); - if (mConfig.isLandscape && mConfig.hasTransposedNavBar) { - mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0); - } else { - mSystemInsets.set(0, mStatusBarHeight, 0, mNavBarHeight); - } + mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), + mSearchBarBounds, mTaskStackBounds); + int systemBarBottomInset = mConfig.hasTransposedNavBar ? 0 : mNavBarHeight; - // Inflate the header bar layout so that we can rebind and draw it for the transition - TaskStack stack = new TaskStack(); - mDummyStackView = new TaskStackView(mContext, stack); + // Rebind the header bar and draw it for the transition TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm(); Rect taskStackBounds = new Rect(mTaskStackBounds); - taskStackBounds.bottom -= mSystemInsets.bottom; + taskStackBounds.bottom -= systemBarBottomInset; algo.computeRects(windowRect.width(), windowRect.height(), taskStackBounds); - Rect taskViewSize = algo.getUntransformedTaskViewSize(); - int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height); - synchronized (mHeaderBarLock) { - mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null, - false); - mHeaderBar.measure( - View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY)); - // TODO: may not be needed - mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight); + Rect taskViewBounds = algo.getUntransformedTaskViewBounds(); + if (!taskViewBounds.equals(mLastTaskViewBounds)) { + mLastTaskViewBounds.set(taskViewBounds); + + int taskViewWidth = taskViewBounds.width(); + synchronized (mHeaderBarLock) { + mHeaderBar.measure( + View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY)); + mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight); + } } } @@ -560,17 +567,17 @@ public class Recents extends SystemUI return; } else { // Otherwise, start the recents activity - startRecentsActivity(topTask, isTopTaskHome.value); + showRecentsActivity(topTask, isTopTaskHome.value); } } - /** Starts the recents activity if it is not already running */ - void startRecentsActivity() { + /** Shows the recents activity if it is not already running */ + void showRecentsActivity() { // Check if the top task is in the home stack, and start the recents activity ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask(); MutableBoolean isTopTaskHome = new MutableBoolean(true); if (topTask == null || !mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) { - startRecentsActivity(topTask, isTopTaskHome.value); + showRecentsActivity(topTask, isTopTaskHome.value); } } @@ -732,30 +739,18 @@ public class Recents extends SystemUI return mTmpTransform; } - /** Starts the recents activity */ - void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) { + /** Shows the recents activity */ + void showRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) { RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); - RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy); + + // Update the header bar if necessary + reloadHeaderBarLayout(false /* tryAndBindSearchWidget */); if (sInstanceLoadPlan == null) { // Create a new load plan if onPreloadRecents() was never triggered sInstanceLoadPlan = loader.createLoadPlan(mContext); } - // Temporarily skip the transition (use a dummy fade) if multi stack is enabled. - // For multi-stack we need to figure out where each of the tasks are going. - if (mConfig.multiWindowEnabled) { - loader.preloadTasks(sInstanceLoadPlan, true); - TaskStack stack = sInstanceLoadPlan.getTaskStack(); - mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, true); - TaskStackViewLayoutAlgorithm.VisibilityReport stackVr = - mDummyStackView.computeStackVisibilityReport(); - ActivityOptions opts = getUnknownTransitionActivityOptions(); - startAlternateRecentsActivity(topTask, opts, true /* fromHome */, - false /* fromSearchHome */, false /* fromThumbnail */, stackVr); - return; - } - if (!sInstanceLoadPlan.hasTasks()) { loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome); } @@ -774,7 +769,7 @@ public class Recents extends SystemUI ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack, mDummyStackView); if (opts != null) { - startAlternateRecentsActivity(topTask, opts, false /* fromHome */, + startRecentsActivity(topTask, opts, false /* fromHome */, false /* fromSearchHome */, true /* fromThumbnail */, stackVr); } else { // Fall through below to the non-thumbnail transition @@ -794,12 +789,12 @@ public class Recents extends SystemUI boolean fromSearchHome = (homeActivityPackage != null) && homeActivityPackage.equals(searchWidgetPackage); ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome); - startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome, + startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome, false /* fromThumbnail */, stackVr); } else { // Otherwise we do the normal fade from an unknown source ActivityOptions opts = getUnknownTransitionActivityOptions(); - startAlternateRecentsActivity(topTask, opts, true /* fromHome */, + startRecentsActivity(topTask, opts, true /* fromHome */, false /* fromSearchHome */, false /* fromThumbnail */, stackVr); } } @@ -807,19 +802,20 @@ public class Recents extends SystemUI } /** Starts the recents activity */ - void startAlternateRecentsActivity(ActivityManager.RunningTaskInfo topTask, - ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail, - TaskStackViewLayoutAlgorithm.VisibilityReport vr) { + void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, + ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail, + TaskStackViewLayoutAlgorithm.VisibilityReport vr) { // Update the configuration based on the launch options - mConfig.launchedFromHome = fromSearchHome || fromHome; - mConfig.launchedFromSearchHome = fromSearchHome; - mConfig.launchedFromAppWithThumbnail = fromThumbnail; - mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1; - mConfig.launchedWithAltTab = mTriggeredFromAltTab; - mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews; - mConfig.launchedNumVisibleTasks = vr.numVisibleTasks; - mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails; - mConfig.launchedHasConfigurationChanged = false; + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + launchState.launchedFromHome = fromSearchHome || fromHome; + launchState.launchedFromSearchHome = fromSearchHome; + launchState.launchedFromAppWithThumbnail = fromThumbnail; + launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1; + launchState.launchedWithAltTab = mTriggeredFromAltTab; + launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews; + launchState.launchedNumVisibleTasks = vr.numVisibleTasks; + launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails; + launchState.launchedHasConfigurationChanged = false; Intent intent = new Intent(sToggleRecentsAction); intent.setClassName(sRecentsPackage, sRecentsActivity); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 4bb3e4ae0dbc..9ce6b2c764b4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -25,27 +25,21 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Configuration; import android.os.Bundle; import android.os.SystemClock; import android.os.UserHandle; import android.view.KeyEvent; import android.view.View; import android.view.ViewStub; -import android.widget.Toast; - import com.android.internal.logging.MetricsLogger; -import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.recents.misc.Console; -import com.android.systemui.recents.misc.DebugTrigger; import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.model.RecentsTaskLoadPlan; import com.android.systemui.recents.model.RecentsTaskLoader; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; -import com.android.systemui.recents.views.DebugOverlayView; import com.android.systemui.recents.views.RecentsView; import com.android.systemui.recents.views.SystemBarScrimViews; import com.android.systemui.recents.views.ViewAnimation; @@ -57,8 +51,7 @@ import java.util.ArrayList; * The main Recents activity that is started from AlternateRecentsComponent. */ public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks, - RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks, - DebugOverlayView.DebugOverlayViewCallbacks { + RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks { RecentsConfiguration mConfig; long mLastTabKeyEventTime; @@ -67,9 +60,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView RecentsView mRecentsView; SystemBarScrimViews mScrimViews; ViewStub mEmptyViewStub; - ViewStub mDebugOverlayStub; View mEmptyView; - DebugOverlayView mDebugOverlay; // Resize task debug RecentsResizeTaskDialog mResizeTaskDebugDialog; @@ -176,16 +167,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } }; - /** - * A custom debug trigger to listen for a debug key chord. - */ - final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() { - @Override - public void run() { - onDebugModeTriggered(); - } - }); - /** Updates the set of recent tasks */ void updateRecentsTasks() { // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent @@ -197,18 +178,19 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } // Start loading tasks according to the load plan + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); if (!plan.hasTasks()) { - loader.preloadTasks(plan, mConfig.launchedFromHome); + loader.preloadTasks(plan, launchState.launchedFromHome); } RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options(); - loadOpts.runningTaskId = mConfig.launchedToTaskId; - loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks; - loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails; + loadOpts.runningTaskId = launchState.launchedToTaskId; + loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks; + loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails; loader.loadTasks(this, plan, loadOpts); TaskStack stack = plan.getTaskStack(); - mConfig.launchedWithNoRecentTasks = !plan.hasTasks(); - if (!mConfig.launchedWithNoRecentTasks) { + launchState.launchedWithNoRecentTasks = !plan.hasTasks(); + if (!launchState.launchedWithNoRecentTasks) { mRecentsView.setTaskStack(stack); } @@ -219,19 +201,19 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, ActivityOptions.makeCustomAnimation(this, - mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter : + launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter : R.anim.recents_to_launcher_enter, - mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit : + launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit : R.anim.recents_to_launcher_exit)); // Mark the task that is the launch target int launchTaskIndexInStack = 0; - if (mConfig.launchedToTaskId != -1) { + if (launchState.launchedToTaskId != -1) { ArrayList<Task> tasks = stack.getTasks(); int taskCount = tasks.size(); for (int j = 0; j < taskCount; j++) { Task t = tasks.get(j); - if (t.key.id == mConfig.launchedToTaskId) { + if (t.key.id == launchState.launchedToTaskId) { t.isLaunchTarget = true; launchTaskIndexInStack = tasks.size() - j - 1; break; @@ -240,7 +222,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } // Update the top level view's visibilities - if (mConfig.launchedWithNoRecentTasks) { + if (launchState.launchedWithNoRecentTasks) { if (mEmptyView == null) { mEmptyView = mEmptyViewStub.inflate(); } @@ -261,13 +243,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mScrimViews.prepareEnterRecentsAnimation(); // Keep track of whether we launched from the nav bar button or via alt-tab - if (mConfig.launchedWithAltTab) { + if (launchState.launchedWithAltTab) { MetricsLogger.count(this, "overview_trigger_alttab", 1); } else { MetricsLogger.count(this, "overview_trigger_nav_btn", 1); } // Keep track of whether we launched from an app or from home - if (mConfig.launchedFromAppWithThumbnail) { + if (launchState.launchedFromAppWithThumbnail) { MetricsLogger.count(this, "overview_source_app", 1); // If from an app, track the stack index of the app in the stack (for affiliated tasks) MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack); @@ -281,6 +263,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView /** Dismisses recents if we are already visible and the intent is to toggle the recents view */ boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) { + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) { // If we currently have filtered stacks, then unfilter those first @@ -289,7 +272,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // If we have a focused Task, launch that Task now if (mRecentsView.launchFocusedTask()) return true; // If we launched from Home, then return to Home - if (mConfig.launchedFromHome) { + if (launchState.launchedFromHome) { dismissRecentsToHomeRaw(true); return true; } @@ -339,7 +322,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // initialized RecentsTaskLoader.initialize(this); SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); - mConfig = RecentsConfiguration.reinitialize(this, ssp); + mConfig = RecentsConfiguration.initialize(this, ssp); + mConfig.update(this, ssp, ssp.getWindowRect()); // Initialize the widget host (the host id is static and does not change) mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId); @@ -352,9 +336,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub); - mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub); - mScrimViews = new SystemBarScrimViews(this, mConfig); - inflateDebugOverlay(); + mScrimViews = new SystemBarScrimViews(this); // Bind the search app widget when we first start up mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost); @@ -366,32 +348,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView registerReceiver(mSystemBroadcastReceiver, filter); } - /** Inflates the debug overlay if debug mode is enabled. */ - void inflateDebugOverlay() { - if (!Constants.DebugFlags.App.EnableDebugMode) return; - - if (mConfig.debugModeEnabled && mDebugOverlay == null) { - // Inflate the overlay and seek bars - mDebugOverlay = (DebugOverlayView) mDebugOverlayStub.inflate(); - mDebugOverlay.setCallbacks(this); - mRecentsView.setDebugOverlay(mDebugOverlay); - } - } - @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); - - // Clear any debug rects - if (mDebugOverlay != null) { - mDebugOverlay.clear(); - } } @Override protected void onStart() { super.onStart(); + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY); RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); SystemServicesProxy ssp = loader.getSystemServicesProxy(); @@ -413,12 +379,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // If this is a new instance from a configuration change, then we have to manually trigger // the enter animation state, or if recents was relaunched by AM, without going through // the normal mechanisms - boolean wasLaunchedByAm = !mConfig.launchedFromHome && !mConfig.launchedFromAppWithThumbnail; - if (mConfig.launchedHasConfigurationChanged || wasLaunchedByAm) { + boolean wasLaunchedByAm = !launchState.launchedFromHome && + !launchState.launchedFromAppWithThumbnail; + if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) { onEnterAnimationTriggered(); } - if (!mConfig.launchedHasConfigurationChanged) { + if (!launchState.launchedHasConfigurationChanged) { mRecentsView.disableLayersForOneFrame(); } } @@ -436,6 +403,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView protected void onStop() { super.onStop(); MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY); + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); SystemServicesProxy ssp = loader.getSystemServicesProxy(); Recents.notifyVisibilityChanged(this, ssp, false); @@ -452,12 +420,12 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Workaround for b/22542869, if the RecentsActivity is started again, but without going // through SystemUI, we need to reset the config launch flags to ensure that we do not // wait on the system to send a signal that was never queued. - mConfig.launchedFromHome = false; - mConfig.launchedFromSearchHome = false; - mConfig.launchedFromAppWithThumbnail = false; - mConfig.launchedToTaskId = -1; - mConfig.launchedWithAltTab = false; - mConfig.launchedHasConfigurationChanged = false; + launchState.launchedFromHome = false; + launchState.launchedFromSearchHome = false; + launchState.launchedFromAppWithThumbnail = false; + launchState.launchedToTaskId = -1; + launchState.launchedWithAltTab = false; + launchState.launchedHasConfigurationChanged = false; } @Override @@ -509,8 +477,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_TAB: { + int altTabKeyDelay = getResources().getInteger(R.integer.recents_alt_tab_key_delay); boolean hasRepKeyTimeElapsed = (SystemClock.elapsedRealtime() - - mLastTabKeyEventTime) > mConfig.altTabKeyDelay; + mLastTabKeyEventTime) > altTabKeyDelay; if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) { // Focus the next task in the stack final boolean backward = event.isShiftPressed(); @@ -538,8 +507,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView default: break; } - // Pass through the debug trigger - mDebugTrigger.onKeyEvent(keyCode); return super.onKeyDown(keyCode, event); } @@ -550,40 +517,10 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView @Override public void onBackPressed() { - // Test mode where back does not do anything - if (mConfig.debugModeEnabled) return; - // Dismiss Recents to the focused Task or Home dismissRecentsToFocusedTaskOrHome(true); } - /** Called when debug mode is triggered */ - public void onDebugModeTriggered() { - if (mConfig.developerOptionsEnabled) { - if (Prefs.getBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, false /* boolean */)) { - // Disable the debug mode - Prefs.remove(this, Prefs.Key.DEBUG_MODE_ENABLED); - mConfig.debugModeEnabled = false; - inflateDebugOverlay(); - if (mDebugOverlay != null) { - mDebugOverlay.disable(); - } - } else { - // Enable the debug mode - Prefs.putBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, true); - mConfig.debugModeEnabled = true; - inflateDebugOverlay(); - if (mDebugOverlay != null) { - mDebugOverlay.enable(); - } - } - Toast.makeText(this, "Debug mode (" + Constants.Values.App.DebugModeVersion + ") " + - (mConfig.debugModeEnabled ? "Enabled" : "Disabled") + ", please restart Recents now", - Toast.LENGTH_SHORT).show(); - } - } - - /**** RecentsResizeTaskDialog ****/ private RecentsResizeTaskDialog getResizeTaskDebugDialog() { @@ -655,16 +592,4 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mRecentsView.setSearchBar(null); } } - - /**** DebugOverlayView.DebugOverlayViewCallbacks ****/ - - @Override - public void onPrimarySeekBarChanged(float progress) { - // Do nothing - } - - @Override - public void onSecondarySeekBarChanged(float progress) { - // Do nothing - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java new file mode 100644 index 000000000000..e2e0e918ab51 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents; + +/** + * The launch state of the RecentsActivity. + * + * TODO: We will be refactoring this out RecentsConfiguration. + * Current Constraints: + * - needed in onStart() before onNewIntent() + * - needs to be reset when Recents is hidden + * - needs to be computed in Recents component + * - needs to be accessible by views + */ +public class RecentsActivityLaunchState { + + public RecentsConfiguration mConfig; + + public boolean launchedWithAltTab; + public boolean launchedWithNoRecentTasks; + public boolean launchedFromAppWithThumbnail; + public boolean launchedFromHome; + public boolean launchedFromSearchHome; + public boolean launchedReuseTaskStackViews; + public boolean launchedHasConfigurationChanged; + public int launchedToTaskId; + public int launchedNumVisibleTasks; + public int launchedNumVisibleThumbnails; + + RecentsActivityLaunchState(RecentsConfiguration config) { + mConfig = config; + } + + /** Called when the configuration has changed, and we want to reset any configuration specific + * members. */ + public void updateOnConfigurationChange() { + // Reset this flag on configuration change to ensure that we recreate new task views + launchedReuseTaskStackViews = false; + // Set this flag to indicate that the configuration has changed since Recents last launched + launchedHasConfigurationChanged = true; + } + + /** Returns whether the status bar scrim should be animated when shown for the first time. */ + public boolean shouldAnimateStatusBarScrim() { + return launchedFromHome; + } + + /** Returns whether the status bar scrim should be visible. */ + public boolean hasStatusBarScrim() { + return !launchedWithNoRecentTasks; + } + + /** Returns whether the nav bar scrim should be animated when shown for the first time. */ + public boolean shouldAnimateNavBarScrim() { + return true; + } + + /** Returns whether the nav bar scrim should be visible. */ + public boolean hasNavBarScrim() { + // Only show the scrim if we have recent tasks, and if the nav bar is not transposed + return !launchedWithNoRecentTasks && mConfig.hasTransposedNavBar; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index b41b5e75e0f6..52b9521b9952 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -16,27 +16,29 @@ package com.android.systemui.recents; -import android.app.ActivityManager; import android.content.Context; -import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; import android.provider.Settings; -import android.util.DisplayMetrics; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; - -import com.android.systemui.Prefs; import com.android.systemui.R; -import com.android.systemui.recents.misc.Console; import com.android.systemui.recents.misc.SystemServicesProxy; - -/** A static Recents configuration for the current context - * NOTE: We should not hold any references to a Context from a static instance */ +/** + * Application resources that can be retrieved from the application context and are not specifically + * tied to the current activity. + */ public class RecentsConfiguration { static RecentsConfiguration sInstance; - static int sPrevConfigurationHashCode; + + private static final int LARGE_SCREEN_MIN_DP = 600; + private static final int XLARGE_SCREEN_MIN_DP = 720; + + // Variables that are used for global calculations + private static final float STACK_SIDE_PADDING_PHONES_PCT = 0.03333f; + private static final float STACK_SIZE_PADDING_TABLETS_PCT = 0.075f; + private static final float STACK_SIZE_PADDING_LARGE_TABLETS_PCT = 0.15f; + private static final int SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS = 64; + private static final int SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS = 72; /** Levels of svelte in increasing severity/austerity. */ // No svelting. @@ -50,123 +52,81 @@ public class RecentsConfiguration { // Disable all thumbnail loading. public static final int SVELTE_DISABLE_LOADING = 3; - /** Interpolators */ - public Interpolator fastOutSlowInInterpolator; - public Interpolator fastOutLinearInInterpolator; - public Interpolator linearOutSlowInInterpolator; - public Interpolator quintOutInterpolator; + // Launch states + public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState(this); - /** Filtering */ - public int filteringCurrentViewsAnimDuration; - public int filteringNewViewsAnimDuration; - - /** Insets */ - public Rect systemInsets = new Rect(); - public Rect displayRect = new Rect(); - - /** Layout */ - boolean isLandscape; + // TODO: Values determined by the current context, needs to be refactored into something that is + // agnostic of the activity context, but still calculable from the Recents component for + // the transition into recents boolean hasTransposedSearchBar; boolean hasTransposedNavBar; - - /** Loading */ - public int maxNumTasksToLoad; - - /** Search bar */ - public int searchBarSpaceHeightPx; - - /** Task stack */ - public int taskStackScrollDuration; - public int taskStackMaxDim; - public int taskStackTopPaddingPx; - public int dismissAllButtonSizePx; public float taskStackWidthPaddingPct; - public float taskStackOverscrollPct; - - /** Transitions */ - public int transitionEnterFromAppDelay; - public int transitionEnterFromHomeDelay; - - /** Task view animation and styles */ - public int taskViewEnterFromAppDuration; - public int taskViewEnterFromHomeDuration; - public int taskViewEnterFromHomeStaggerDelay; - public int taskViewExitToAppDuration; - public int taskViewExitToHomeDuration; - public int taskViewRemoveAnimDuration; - public int taskViewRemoveAnimTranslationXPx; - public int taskViewTranslationZMinPx; - public int taskViewTranslationZMaxPx; - public int taskViewRoundedCornerRadiusPx; - public int taskViewHighlightPx; - public int taskViewAffiliateGroupEnterOffsetPx; - public float taskViewThumbnailAlpha; - - /** Task bar colors */ - public int taskBarViewDefaultBackgroundColor; - public int taskBarViewLightTextColor; - public int taskBarViewDarkTextColor; - public int taskBarViewHighlightColor; - public float taskBarViewAffiliationColorMinAlpha; - /** Task bar size & animations */ - public int taskBarHeight; - public int taskBarDismissDozeDelaySeconds; - - /** Nav bar scrim */ - public int navBarScrimEnterDuration; - - /** Launch states */ - public boolean launchedWithAltTab; - public boolean launchedWithNoRecentTasks; - public boolean launchedFromAppWithThumbnail; - public boolean launchedFromHome; - public boolean launchedFromSearchHome; - public boolean launchedReuseTaskStackViews; - public boolean launchedHasConfigurationChanged; - public int launchedToTaskId; - public int launchedNumVisibleTasks; - public int launchedNumVisibleThumbnails; + // Since the positions in Recents has to be calculated globally (before the RecentsActivity + // starts), we need to calculate some resource values ourselves, instead of relying on framework + // resources. + public final boolean isLargeScreen; + public final boolean isXLargeScreen; + public final int smallestWidth; /** Misc **/ public boolean useHardwareLayers; - public int altTabKeyDelay; public boolean fakeShadows; + public int svelteLevel; + public int searchBarSpaceHeightPx; /** Dev options and global settings */ public boolean multiWindowEnabled; public boolean lockToAppEnabled; - public boolean developerOptionsEnabled; - public boolean debugModeEnabled; - public int svelteLevel; /** Private constructor */ - private RecentsConfiguration(Context context) { - // Properties that don't have to be reloaded with each configuration change can be loaded - // here. + private RecentsConfiguration(Context context, SystemServicesProxy ssp) { + // Load only resources that can not change after the first load either through developer + // settings or via multi window + Context appContext = context.getApplicationContext(); + Resources res = appContext.getResources(); + useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers); + fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows); + svelteLevel = res.getInteger(R.integer.recents_svelte_level); + + float density = context.getResources().getDisplayMetrics().density; + smallestWidth = ssp.getDeviceSmallestWidth(); + isLargeScreen = smallestWidth >= (int) (density * LARGE_SCREEN_MIN_DP); + isXLargeScreen = smallestWidth >= (int) (density * XLARGE_SCREEN_MIN_DP); + searchBarSpaceHeightPx = isLargeScreen ? + (int) (density * SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS) : + (int) (density * SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS); + if (isLargeScreen) { + taskStackWidthPaddingPct = STACK_SIZE_PADDING_TABLETS_PCT; + } else if (isXLargeScreen) { + taskStackWidthPaddingPct = STACK_SIZE_PADDING_LARGE_TABLETS_PCT; + } else { + taskStackWidthPaddingPct = STACK_SIDE_PADDING_PHONES_PCT; + } + } + + /** + * Updates the configuration based on the current state of the system + */ + void update(Context context, SystemServicesProxy ssp, Rect windowRect) { + // Only update resources that can change after the first load, either through developer + // settings or via multi window + lockToAppEnabled = ssp.getSystemSetting(context, + Settings.System.LOCK_TO_APP_ENABLED) != 0; + multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window")); - // Interpolators - fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, - com.android.internal.R.interpolator.fast_out_slow_in); - fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, - com.android.internal.R.interpolator.fast_out_linear_in); - linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, - com.android.internal.R.interpolator.linear_out_slow_in); - quintOutInterpolator = AnimationUtils.loadInterpolator(context, - com.android.internal.R.interpolator.decelerate_quint); + // Recompute some values based on the given state, since we can not rely on the resource + // system to get certain values. + boolean isLandscape = windowRect.width() > windowRect.height(); + hasTransposedNavBar = isLandscape && isLargeScreen && !isXLargeScreen; + hasTransposedSearchBar = isLandscape && isLargeScreen && !isXLargeScreen; } /** Updates the configuration to the current context */ - public static RecentsConfiguration reinitialize(Context context, SystemServicesProxy ssp) { + public static RecentsConfiguration initialize(Context context, SystemServicesProxy ssp) { if (sInstance == null) { - sInstance = new RecentsConfiguration(context); + sInstance = new RecentsConfiguration(context, ssp); } - int configHashCode = context.getResources().getConfiguration().hashCode(); - if (sPrevConfigurationHashCode != configHashCode) { - sInstance.update(context); - sPrevConfigurationHashCode = configHashCode; - } - sInstance.updateOnReinitialize(context, ssp); return sInstance; } @@ -175,145 +135,18 @@ public class RecentsConfiguration { return sInstance; } - /** Updates the state, given the specified context */ - void update(Context context) { - Resources res = context.getResources(); - DisplayMetrics dm = res.getDisplayMetrics(); - - // Debug mode - debugModeEnabled = Prefs.getBoolean(context, Prefs.Key.DEBUG_MODE_ENABLED, - false /* defaultValue */); - if (debugModeEnabled) { - Console.Enabled = true; - } - - // Layout - isLandscape = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; - hasTransposedSearchBar = res.getBoolean(R.bool.recents_has_transposed_search_bar); - hasTransposedNavBar = res.getBoolean(R.bool.recents_has_transposed_nav_bar); - - // Insets - displayRect.set(0, 0, dm.widthPixels, dm.heightPixels); - - // Filtering - filteringCurrentViewsAnimDuration = - res.getInteger(R.integer.recents_filter_animate_current_views_duration); - filteringNewViewsAnimDuration = - res.getInteger(R.integer.recents_filter_animate_new_views_duration); - - // Loading - maxNumTasksToLoad = ActivityManager.getMaxRecentTasksStatic(); - - // Search Bar - searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height); - - // Task stack - taskStackScrollDuration = - res.getInteger(R.integer.recents_animate_task_stack_scroll_duration); - taskStackWidthPaddingPct = res.getFloat(R.dimen.recents_stack_width_padding_percentage); - taskStackOverscrollPct = res.getFloat(R.dimen.recents_stack_overscroll_percentage); - taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim); - taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding); - dismissAllButtonSizePx = res.getDimensionPixelSize(R.dimen.recents_dismiss_all_button_size); - - // Transition - transitionEnterFromAppDelay = - res.getInteger(R.integer.recents_enter_from_app_transition_duration); - transitionEnterFromHomeDelay = - res.getInteger(R.integer.recents_enter_from_home_transition_duration); - - // Task view animation and styles - taskViewEnterFromAppDuration = - res.getInteger(R.integer.recents_task_enter_from_app_duration); - taskViewEnterFromHomeDuration = - res.getInteger(R.integer.recents_task_enter_from_home_duration); - taskViewEnterFromHomeStaggerDelay = - res.getInteger(R.integer.recents_task_enter_from_home_stagger_delay); - taskViewExitToAppDuration = - res.getInteger(R.integer.recents_task_exit_to_app_duration); - taskViewExitToHomeDuration = - res.getInteger(R.integer.recents_task_exit_to_home_duration); - taskViewRemoveAnimDuration = - res.getInteger(R.integer.recents_animate_task_view_remove_duration); - taskViewRemoveAnimTranslationXPx = - res.getDimensionPixelSize(R.dimen.recents_task_view_remove_anim_translation_x); - taskViewRoundedCornerRadiusPx = - res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); - taskViewHighlightPx = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight); - taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min); - taskViewTranslationZMaxPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max); - taskViewAffiliateGroupEnterOffsetPx = - res.getDimensionPixelSize(R.dimen.recents_task_view_affiliate_group_enter_offset); - taskViewThumbnailAlpha = res.getFloat(R.dimen.recents_task_view_thumbnail_alpha); - - // Task bar colors - taskBarViewDefaultBackgroundColor = context.getColor( - R.color.recents_task_bar_default_background_color); - taskBarViewLightTextColor = context.getColor(R.color.recents_task_bar_light_text_color); - taskBarViewDarkTextColor = context.getColor(R.color.recents_task_bar_dark_text_color); - taskBarViewHighlightColor = context.getColor(R.color.recents_task_bar_highlight_color); - taskBarViewAffiliationColorMinAlpha = res.getFloat( - R.dimen.recents_task_affiliation_color_min_alpha_percentage); - - // Task bar size & animations - taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height); - taskBarDismissDozeDelaySeconds = - res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds); - - // Nav bar scrim - navBarScrimEnterDuration = - res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration); - - // Misc - useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers); - altTabKeyDelay = res.getInteger(R.integer.recents_alt_tab_key_delay); - fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows); - svelteLevel = res.getInteger(R.integer.recents_svelte_level); - } - - /** Updates the system insets */ - public void updateSystemInsets(Rect insets) { - systemInsets.set(insets); - } - - /** Updates the states that need to be re-read whenever we re-initialize. */ - void updateOnReinitialize(Context context, SystemServicesProxy ssp) { - // Check if the developer options are enabled - developerOptionsEnabled = ssp.getGlobalSetting(context, - Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0; - lockToAppEnabled = ssp.getSystemSetting(context, - Settings.System.LOCK_TO_APP_ENABLED) != 0; - multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window")); + /** + * Returns the activity launch state. + * TODO: This will be refactored out of RecentsConfiguration. + */ + public RecentsActivityLaunchState getLaunchState() { + return mLaunchState; } /** Called when the configuration has changed, and we want to reset any configuration specific * members. */ public void updateOnConfigurationChange() { - // Reset this flag on configuration change to ensure that we recreate new task views - launchedReuseTaskStackViews = false; - // Set this flag to indicate that the configuration has changed since Recents last launched - launchedHasConfigurationChanged = true; - } - - /** Returns whether the status bar scrim should be animated when shown for the first time. */ - public boolean shouldAnimateStatusBarScrim() { - return launchedFromHome; - } - - /** Returns whether the status bar scrim should be visible. */ - public boolean hasStatusBarScrim() { - return !launchedWithNoRecentTasks; - } - - /** Returns whether the nav bar scrim should be animated when shown for the first time. */ - public boolean shouldAnimateNavBarScrim() { - return true; - } - - /** Returns whether the nav bar scrim should be visible. */ - public boolean hasNavBarScrim() { - // Only show the scrim if we have recent tasks, and if the nav bar is not transposed - return !launchedWithNoRecentTasks && (!hasTransposedNavBar || !isLandscape); + mLaunchState.updateOnConfigurationChange(); } /** @@ -322,14 +155,17 @@ public class RecentsConfiguration { */ public void getAvailableTaskStackBounds(Rect windowBounds, int topInset, int rightInset, Rect searchBarBounds, Rect taskStackBounds) { - if (isLandscape && hasTransposedSearchBar) { - // In landscape, the search bar appears on the left, but we overlay it on top - taskStackBounds.set(windowBounds.left, windowBounds.top + topInset, - windowBounds.right - rightInset, windowBounds.bottom); + if (hasTransposedNavBar) { + // In landscape phones, the search bar appears on the left, but we overlay it on top + int swInset = getInsetToSmallestWidth(windowBounds.right - rightInset - + windowBounds.left); + taskStackBounds.set(windowBounds.left + swInset, windowBounds.top + topInset, + windowBounds.right - swInset - rightInset, windowBounds.bottom); } else { // In portrait, the search bar appears on the top (which already has the inset) - taskStackBounds.set(windowBounds.left, searchBarBounds.bottom, - windowBounds.right, windowBounds.bottom); + int swInset = getInsetToSmallestWidth(windowBounds.right - windowBounds.left); + taskStackBounds.set(windowBounds.left + swInset, searchBarBounds.bottom, + windowBounds.right - swInset, windowBounds.bottom); } } @@ -340,8 +176,8 @@ public class RecentsConfiguration { public void getSearchBarBounds(Rect windowBounds, int topInset, Rect searchBarSpaceBounds) { // Return empty rects if search is not enabled int searchBarSize = searchBarSpaceHeightPx; - if (isLandscape && hasTransposedSearchBar) { - // In landscape, the search bar appears on the left + if (hasTransposedSearchBar) { + // In landscape phones, the search bar appears on the left searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset, windowBounds.left + searchBarSize, windowBounds.bottom); } else { @@ -350,4 +186,14 @@ public class RecentsConfiguration { windowBounds.right, windowBounds.top + topInset + searchBarSize); } } + + /** + * Constrain the width of the landscape stack to the smallest width of the device. + */ + private int getInsetToSmallestWidth(int availableWidth) { + if (availableWidth > smallestWidth) { + return (availableWidth - smallestWidth) / 2; + } + return 0; + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java index 703c7d27312f..59df293f71d7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java @@ -16,17 +16,18 @@ package com.android.systemui.recents; +import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.app.FragmentManager; -import android.content.Context; import android.content.DialogInterface; import android.graphics.Rect; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; +import android.widget.Toast; import com.android.systemui.R; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.model.RecentsTaskLoader; @@ -50,10 +51,18 @@ public class RecentsResizeTaskDialog extends DialogFragment { private static final int PLACE_BOTTOM_LEFT = 7; private static final int PLACE_BOTTOM_RIGHT = 8; private static final int PLACE_FULL = 9; + private static final int PLACE_DOCK_LEFT = 10; + private static final int PLACE_DOCK_RIGHT = 11; + private static final int PLACE_DOCK_TOP = 12; + private static final int PLACE_DOCK_BOTTOM = 13; // The button resource ID combined with the arrangement command. private static final int[][] BUTTON_DEFINITIONS = - {{R.id.place_left, PLACE_LEFT}, + {{R.id.place_dock_left, PLACE_DOCK_LEFT}, + {R.id.place_dock_right, PLACE_DOCK_RIGHT}, + {R.id.place_dock_top, PLACE_DOCK_TOP}, + {R.id.place_dock_bottom, PLACE_DOCK_BOTTOM}, + {R.id.place_left, PLACE_LEFT}, {R.id.place_right, PLACE_RIGHT}, {R.id.place_top, PLACE_TOP}, {R.id.place_bottom, PLACE_BOTTOM}, @@ -72,6 +81,12 @@ public class RecentsResizeTaskDialog extends DialogFragment { private Rect[] mBounds = {new Rect(), new Rect(), new Rect(), new Rect()}; private Task[] mTasks = {null, null, null, null}; + /** + * Called by FragmentManager + */ + public RecentsResizeTaskDialog() { + } + public RecentsResizeTaskDialog(FragmentManager mgr, RecentsActivity activity) { mFragmentManager = mgr; mRecentsActivity = activity; @@ -82,13 +97,11 @@ public class RecentsResizeTaskDialog extends DialogFragment { void showResizeTaskDialog(Task mainTask, RecentsView rv) { mTasks[0] = mainTask; mRecentsView = rv; - - show(mFragmentManager, TAG); + showAllowingStateLoss(mFragmentManager, TAG); } /** Creates a new resize-task dialog. */ - private void createResizeTaskDialog(final Context context, LayoutInflater inflater, - AlertDialog.Builder builder) { + private void createResizeTaskDialog(LayoutInflater inflater, AlertDialog.Builder builder) { builder.setTitle(R.string.recents_caption_resize); mResizeTaskDialogContent = inflater.inflate(R.layout.recents_task_resize_dialog, null, false); @@ -100,7 +113,17 @@ public class RecentsResizeTaskDialog extends DialogFragment { b.setOnClickListener( new View.OnClickListener() { public void onClick(View v) { - placeTasks(action); + switch (action) { + case PLACE_DOCK_LEFT: + case PLACE_DOCK_RIGHT: + case PLACE_DOCK_TOP: + case PLACE_DOCK_BOTTOM: + placeDockTasks(action); + break; + default: + placeTasks(action); + break; + } } }); } @@ -109,7 +132,7 @@ public class RecentsResizeTaskDialog extends DialogFragment { builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - dismiss(); + dismissAllowingStateLoss(); } }); @@ -118,7 +141,7 @@ public class RecentsResizeTaskDialog extends DialogFragment { /** Helper function to place window(s) on the display according to an arrangement request. */ private void placeTasks(int arrangement) { - Rect rect = mSsp.getWindowRect(); + Rect rect = mSsp.getDisplayRect(); for (int i = 0; i < mBounds.length; ++i) { mBounds[i].set(rect); if (i != 0) { @@ -193,7 +216,7 @@ public class RecentsResizeTaskDialog extends DialogFragment { break; case PLACE_FULL: // Nothing to change. - mBounds[0] = null; + mBounds[0] = new Rect(); break; } @@ -207,7 +230,7 @@ public class RecentsResizeTaskDialog extends DialogFragment { } // Get rid of the dialog. - dismiss(); + dismissAllowingStateLoss(); mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation(); // In debug mode, we force all task to be resizeable regardless of the @@ -229,12 +252,44 @@ public class RecentsResizeTaskDialog extends DialogFragment { } } + /** + * Helper function to place docked window(s) on the display according to an arrangement request. + */ + private void placeDockTasks(int arrangement) { + int createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; + switch (arrangement) { + case PLACE_DOCK_LEFT: + createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; + break; + case PLACE_DOCK_TOP: + createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; + break; + case PLACE_DOCK_RIGHT: + createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; + break; + case PLACE_DOCK_BOTTOM: + createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; + break; + } + + // Dismiss the dialog before trying to launch the task + dismissAllowingStateLoss(); + + if (mTasks[0].key.stackId != ActivityManager.DOCKED_STACK_ID) { + int taskId = mTasks[0].key.id; + mSsp.setTaskResizeable(taskId); + mSsp.dockTask(taskId, createMode); + mRecentsView.launchTask(mTasks[0], null); + } else { + Toast.makeText(getContext(), "Already docked", Toast.LENGTH_SHORT); + } + } + @Override public Dialog onCreateDialog(Bundle args) { - final Context context = this.getActivity(); LayoutInflater inflater = getActivity().getLayoutInflater(); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - createResizeTaskDialog(context, inflater, builder); + createResizeTaskDialog(inflater, builder); return builder.create(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index cbf5c058d102..231843ea2690 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -39,7 +39,6 @@ import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; - import com.android.systemui.R; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java deleted file mode 100644 index fbf8a8669b70..000000000000 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.recents.misc; - -import android.os.Handler; -import android.os.SystemClock; -import android.view.KeyEvent; -import com.android.systemui.recents.Constants; - -/** - * A trigger for catching a debug chord. - * We currently use volume up then volume down to trigger this mode. - */ -public class DebugTrigger { - - Handler mHandler; - Runnable mTriggeredRunnable; - - int mLastKeyCode; - long mLastKeyCodeTime; - - public DebugTrigger(Runnable triggeredRunnable) { - mHandler = new Handler(); - mTriggeredRunnable = triggeredRunnable; - } - - /** Resets the debug trigger */ - void reset() { - mLastKeyCode = 0; - mLastKeyCodeTime = 0; - } - - /** - * Processes a key event and tests if it is a part of the trigger. If the chord is complete, - * then we just call the callback. - */ - public void onKeyEvent(int keyCode) { - if (!Constants.DebugFlags.App.EnableDebugMode) return; - - if (mLastKeyCode == 0) { - if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { - mLastKeyCode = keyCode; - mLastKeyCodeTime = SystemClock.uptimeMillis(); - return; - } - } else { - if (mLastKeyCode == KeyEvent.KEYCODE_VOLUME_UP && - keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { - if ((SystemClock.uptimeMillis() - mLastKeyCodeTime) < 750) { - mTriggeredRunnable.run(); - } - } - } - reset(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 5790ca63e4f2..b6d25f507cb9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -55,18 +55,18 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.util.MutableBoolean; +import android.util.MutableFloat; +import android.util.MutableInt; import android.util.Pair; -import android.util.SparseArray; +import android.util.Size; import android.view.Display; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; - import com.android.internal.app.AssistUtils; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.RecentsConfiguration; import java.io.IOException; import java.util.ArrayList; @@ -282,6 +282,30 @@ public class SystemServicesProxy { } } + /** + * Resizes the given task to the new bounds. + */ + public void resizeTask(int taskId, Rect bounds) { + if (mIam == null) return; + + try { + mIam.resizeTask(taskId, bounds, ActivityManager.RESIZE_MODE_FORCED); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + /** Docks a task to the side of the screen. */ + public void dockTask(int taskId, int createMode) { + if (mIam == null) return; + + try { + mIam.moveTaskToDockedStack(taskId, createMode, true); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + /** Returns the focused stack id. */ public int getFocusedStack() { if (mIam == null) return -1; @@ -637,7 +661,32 @@ public class SystemServicesProxy { } /** - * Returns the window rect. + * Returns the smallest width/height. + */ + public int getDeviceSmallestWidth() { + if (mWm == null) return 0; + + Point smallestSizeRange = new Point(); + Point largestSizeRange = new Point(); + mWm.getDefaultDisplay().getCurrentSizeRange(smallestSizeRange, largestSizeRange); + return smallestSizeRange.x; + } + + /** + * Returns the display rect. + */ + public Rect getDisplayRect() { + Rect displayRect = new Rect(); + if (mWm == null) return displayRect; + + Point p = new Point(); + mWm.getDefaultDisplay().getRealSize(p); + displayRect.set(0, 0, p.x, p.y); + return displayRect; + } + + /** + * Returns the window rect for the RecentsActivity, based on the dimensions of the home stack. */ public Rect getWindowRect() { Rect windowRect = new Rect(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index 649cb4db0fb1..6ef725306815 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -23,7 +23,6 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.util.Log; -import android.util.SparseArray; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.misc.SystemServicesProxy; @@ -76,7 +75,7 @@ public class RecentsTaskLoadPlan { * An optimization to preload the raw list of tasks. */ public synchronized void preloadRawTasks(boolean isTopTaskHome) { - mRawTasks = mSystemServicesProxy.getRecentTasks(mConfig.maxNumTasksToLoad, + mRawTasks = mSystemServicesProxy.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), UserHandle.CURRENT.getIdentifier(), isTopTaskHome); Collections.reverse(mRawTasks); @@ -125,7 +124,7 @@ public class RecentsTaskLoadPlan { activityLabel, mSystemServicesProxy, res); Drawable activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, mSystemServicesProxy, res, infoHandle, false); - int activityColor = loader.getActivityPrimaryColor(t.taskDescription, mConfig); + int activityColor = loader.getActivityPrimaryColor(t.taskDescription, res); // Update the activity info cache if (!hadCachedActivityInfo && infoHandle.info != null) { @@ -153,7 +152,7 @@ public class RecentsTaskLoadPlan { // Initialize the stacks mStack = new TaskStack(); mStack.setTasks(stackTasks); - mStack.createAffiliatedGroupings(mConfig); + mStack.createAffiliatedGroupings(mContext); } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java index ad25c85860ed..760382ed469e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -27,7 +27,6 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.HandlerThread; import android.util.Log; - import com.android.systemui.R; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; @@ -248,7 +247,7 @@ class TaskResourceLoader implements Runnable { } /* Recents task loader - * NOTE: We should not hold any references to a Context from a static instance */ + * NOTE: We should not hold any references to non-application Context from a static instance */ public class RecentsTaskLoader { private static final String TAG = "RecentsTaskLoader"; @@ -438,12 +437,11 @@ public class RecentsTaskLoader { } /** Returns the activity's primary color. */ - public int getActivityPrimaryColor(ActivityManager.TaskDescription td, - RecentsConfiguration config) { + public int getActivityPrimaryColor(ActivityManager.TaskDescription td, Resources res) { if (td != null && td.getPrimaryColor() != 0) { return td.getPrimaryColor(); } - return config.taskBarViewDefaultBackgroundColor; + return res.getColor(R.color.recents_task_bar_default_background_color); } /** Returns the size of the app icon cache. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index a760a4133e81..20d9203ef71f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -16,12 +16,12 @@ package com.android.systemui.recents.model; +import android.content.Context; import android.graphics.Color; -import android.graphics.Rect; import com.android.systemui.recents.Constants; -import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.misc.NamedCounter; import com.android.systemui.recents.misc.Utilities; +import com.android.systemui.R; import java.util.ArrayList; import java.util.Collections; @@ -368,7 +368,7 @@ public class TaskStack { /** * Temporary: This method will simulate affiliation groups by */ - public void createAffiliatedGroupings(RecentsConfiguration config) { + public void createAffiliatedGroupings(Context context) { if (Constants.DebugFlags.App.EnableSimulatedTaskGroups) { HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>(); // Sort all tasks by increasing firstActiveTime of the task @@ -453,7 +453,8 @@ public class TaskStack { tasksMap.put(t.key, t); } // Update the task colors for each of the groups - float minAlpha = config.taskBarViewAffiliationColorMinAlpha; + float minAlpha = context.getResources().getFloat( + R.dimen.recents_task_affiliation_color_min_alpha_percentage); int taskGroupCount = mGroups.size(); for (int i = 0; i < taskGroupCount; i++) { TaskGrouping group = mGroups.get(i); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java b/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java deleted file mode 100644 index 452830d3b5fd..000000000000 --- a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.recents.views; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Pair; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.SeekBar; -import com.android.systemui.R; -import com.android.systemui.recents.RecentsConfiguration; - -import java.util.ArrayList; - -/** - * A full screen overlay layer that allows us to draw views from throughout the system on the top - * most layer. - */ -public class DebugOverlayView extends FrameLayout implements SeekBar.OnSeekBarChangeListener { - - public interface DebugOverlayViewCallbacks { - public void onPrimarySeekBarChanged(float progress); - public void onSecondarySeekBarChanged(float progress); - } - - final static int sCornerRectSize = 50; - - RecentsConfiguration mConfig; - DebugOverlayViewCallbacks mCb; - - ArrayList<Pair<Rect, Integer>> mRects = new ArrayList<Pair<Rect, Integer>>(); - String mText; - Paint mDebugOutline = new Paint(); - Paint mTmpPaint = new Paint(); - Rect mTmpRect = new Rect(); - boolean mEnabled = true; - - SeekBar mPrimarySeekBar; - SeekBar mSecondarySeekBar; - - public DebugOverlayView(Context context) { - this(context, null); - } - - public DebugOverlayView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - mConfig = RecentsConfiguration.getInstance(); - mDebugOutline.setColor(0xFFff0000); - mDebugOutline.setStyle(Paint.Style.STROKE); - mDebugOutline.setStrokeWidth(8f); - setWillNotDraw(false); - } - - public void setCallbacks(DebugOverlayViewCallbacks cb) { - mCb = cb; - } - - @Override - protected void onFinishInflate() { - mPrimarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_1); - mPrimarySeekBar.setOnSeekBarChangeListener(this); - mSecondarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_2); - mSecondarySeekBar.setOnSeekBarChangeListener(this); - } - - /** Enables the debug overlay drawing. */ - public void enable() { - mEnabled = true; - setVisibility(View.VISIBLE); - } - - /** Disables the debug overlay drawing. */ - public void disable() { - mEnabled = false; - setVisibility(View.GONE); - } - - /** Clears all debug rects. */ - public void clear() { - mRects.clear(); - } - - /** Adds a rect to be drawn. */ - void addRect(Rect r, int color) { - mRects.add(new Pair<Rect, Integer>(r, color)); - invalidate(); - } - - /** Adds a view's global rect to be drawn. */ - void addViewRect(View v, int color) { - Rect vr = new Rect(); - v.getGlobalVisibleRect(vr); - mRects.add(new Pair<Rect, Integer>(vr, color)); - invalidate(); - } - - /** Adds a rect, relative to a given view to be drawn. */ - void addRectRelativeToView(View v, Rect r, int color) { - Rect vr = new Rect(); - v.getGlobalVisibleRect(vr); - r.offsetTo(vr.left, vr.top); - mRects.add(new Pair<Rect, Integer>(r, color)); - invalidate(); - } - - /** Sets the debug text at the bottom of the screen. */ - void setText(String message) { - mText = message; - invalidate(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - addRect(new Rect(0, 0, sCornerRectSize, sCornerRectSize), 0xFFff0000); - addRect(new Rect(getMeasuredWidth() - sCornerRectSize, getMeasuredHeight() - sCornerRectSize, - getMeasuredWidth(), getMeasuredHeight()), 0xFFff0000); - } - - @Override - protected void onDraw(Canvas canvas) { - if (mEnabled) { - // Draw the outline - canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mDebugOutline); - - // Draw the rects - int numRects = mRects.size(); - for (int i = 0; i < numRects; i++) { - Pair<Rect, Integer> r = mRects.get(i); - mTmpPaint.setColor(r.second); - canvas.drawRect(r.first, mTmpPaint); - } - - // Draw the text - if (mText != null && mText.length() > 0) { - mTmpPaint.setColor(0xFFff0000); - mTmpPaint.setTextSize(60); - mTmpPaint.getTextBounds(mText, 0, 1, mTmpRect); - canvas.drawText(mText, 10f, getMeasuredHeight() - mTmpRect.height() - mConfig.systemInsets.bottom, mTmpPaint); - } - } - } - - /**** SeekBar.OnSeekBarChangeListener Implementation ****/ - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - // Do nothing - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - // Do nothing - } - - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (seekBar == mPrimarySeekBar) { - mCb.onPrimarySeekBarChanged((float) progress / mPrimarySeekBar.getMax()); - } else if (seekBar == mSecondarySeekBar) { - mCb.onSecondarySeekBarChanged((float) progress / mSecondarySeekBar.getMax()); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java index 509ad1b638f2..682fd8fe1724 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java @@ -28,7 +28,6 @@ import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.util.Log; - import com.android.systemui.R; import com.android.systemui.recents.RecentsConfiguration; @@ -90,7 +89,8 @@ class FakeShadowDrawable extends Drawable { mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); mCornerShadowPaint.setStyle(Paint.Style.FILL); mCornerShadowPaint.setDither(true); - mCornerRadius = config.taskViewRoundedCornerRadiusPx; + mCornerRadius = resources.getDimensionPixelSize( + R.dimen.recents_task_view_rounded_corners_radius); mCardBounds = new RectF(); mEdgeShadowPaint = new Paint(mCornerShadowPaint); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index c7d1dd1452da..73c9be94eeae 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -38,8 +38,9 @@ import android.view.LayoutInflater; import android.view.View; import android.view.WindowInsets; import android.view.WindowManagerGlobal; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.widget.FrameLayout; - import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.recents.Constants; @@ -78,12 +79,14 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV RecentsConfiguration mConfig; LayoutInflater mInflater; - DebugOverlayView mDebugOverlay; ArrayList<TaskStack> mStacks; TaskStackView mTaskStackView; RecentsAppWidgetHostView mSearchBar; RecentsViewCallbacks mCb; + Interpolator mFastOutSlowInInterpolator; + + Rect mSystemInsets = new Rect(); public RecentsView(Context context) { super(context); @@ -101,6 +104,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV super(context, attrs, defStyleAttr, defStyleRes); mConfig = RecentsConfiguration.getInstance(); mInflater = LayoutInflater.from(context); + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_slow_in); } /** Sets the callbacks */ @@ -108,14 +113,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV mCb = cb; } - /** Sets the debug overlay */ - public void setDebugOverlay(DebugOverlayView overlay) { - mDebugOverlay = overlay; - } - /** Set/get the bsp root node */ public void setTaskStack(TaskStack stack) { - if (mConfig.launchedReuseTaskStackViews) { + if (mConfig.getLaunchState().launchedReuseTaskStackViews) { if (mTaskStackView != null) { // If onRecentsHidden is not triggered, we need to the stack view again here mTaskStackView.reset(); @@ -134,11 +134,6 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV addView(mTaskStackView); } - // Enable debug mode drawing on all the stacks if necessary - if (mConfig.debugModeEnabled) { - mTaskStackView.setDebugOverlay(mDebugOverlay); - } - // Trigger a new layout requestLayout(); } @@ -195,7 +190,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV for (int j = 0; j < taskViewCount; j++) { TaskView tv = taskViews.get(j); if (tv.getTask() == task) { - onTaskViewClicked(mTaskStackView, tv, stack, task, false, true, taskBounds); + onTaskViewClicked(mTaskStackView, tv, stack, task, false, taskBounds != null, + taskBounds); return true; } } @@ -288,7 +284,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // Get the search bar bounds and measure the search bar layout Rect searchBarSpaceBounds = new Rect(); if (mSearchBar != null) { - mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top, + mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top, searchBarSpaceBounds); mSearchBar.measure( MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY), @@ -296,8 +292,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } Rect taskStackBounds = new Rect(); - mConfig.getAvailableTaskStackBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top, - mConfig.systemInsets.right, searchBarSpaceBounds, taskStackBounds); + mConfig.getAvailableTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top, + mSystemInsets.right, searchBarSpaceBounds, taskStackBounds); if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) { mTaskStackView.setTaskStackBounds(taskStackBounds); mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec); @@ -316,7 +312,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV Rect searchBarSpaceBounds = new Rect(); if (mSearchBar != null) { mConfig.getSearchBarBounds(measuredRect, - mConfig.systemInsets.top, searchBarSpaceBounds); + mSystemInsets.top, searchBarSpaceBounds); mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top, searchBarSpaceBounds.right, searchBarSpaceBounds.bottom); } @@ -328,8 +324,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { - // Update the configuration with the latest system insets and trigger a relayout - mConfig.updateSystemInsets(insets.getSystemWindowInsets()); + mSystemInsets.set(insets.getSystemWindowInsets()); requestLayout(); return insets.consumeSystemWindowInsets(); } @@ -558,7 +553,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // outside the display rect (to ensure we don't animate from too far away) sourceView = stackView; offsetX = transform.rect.left; - offsetY = mConfig.displayRect.height(); + offsetY = getMeasuredHeight(); } else { sourceView = tv.mThumbnailView; } @@ -589,22 +584,15 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV } postDrawHeaderThumbnailTransitionRunnable(stackView, tv, offsetX, offsetY, stackScroll, animStartedListener); - if (mConfig.multiWindowEnabled) { - opts = ActivityOptions.makeCustomAnimation(sourceView.getContext(), - R.anim.recents_from_unknown_enter, - R.anim.recents_from_unknown_exit, - sourceView.getHandler(), animStartedListener); - } else { - opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView, - Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(), - offsetX, offsetY, transform.rect.width(), transform.rect.height(), - sourceView.getHandler(), animStartedListener); - } + opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView, + Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(), + offsetX, offsetY, transform.rect.width(), transform.rect.height(), + sourceView.getHandler(), animStartedListener); } else { opts = ActivityOptions.makeBasic(); } if (boundsValid) { - opts.setBounds(bounds); + opts.setBounds(bounds.isEmpty() ? null : bounds); } final ActivityOptions launchOpts = opts; final boolean screenPinningRequested = (animStartedListener == null) && lockToTask; @@ -710,11 +698,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV public void onTaskStackFilterTriggered() { // Hide the search bar if (mSearchBar != null) { + int filterDuration = getResources().getInteger( + R.integer.recents_filter_animate_current_views_duration); mSearchBar.animate() .alpha(0f) .setStartDelay(0) - .setInterpolator(mConfig.fastOutSlowInInterpolator) - .setDuration(mConfig.filteringCurrentViewsAnimDuration) + .setInterpolator(mFastOutSlowInInterpolator) + .setDuration(filterDuration) .withLayer() .start(); } @@ -724,11 +714,13 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV public void onTaskStackUnfilterTriggered() { // Show the search bar if (mSearchBar != null) { + int filterDuration = getResources().getInteger( + R.integer.recents_filter_animate_new_views_duration); mSearchBar.animate() .alpha(1f) .setStartDelay(0) - .setInterpolator(mConfig.fastOutSlowInInterpolator) - .setDuration(mConfig.filteringNewViewsAnimDuration) + .setInterpolator(mFastOutSlowInInterpolator) + .setDuration(filterDuration) .withLayer() .start(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java index 0428b48490d6..e04699c10fdd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java @@ -22,13 +22,15 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.annotation.TargetApi; +import android.content.Context; import android.os.Build; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; -import com.android.systemui.recents.RecentsConfiguration; /** * This class facilitates swipe to dismiss. It defines an interface to be implemented by the @@ -46,6 +48,7 @@ public class SwipeHelper { public static final int Y = 1; private static LinearInterpolator sLinearInterpolator = new LinearInterpolator(); + private Interpolator mLinearOutSlowInInterpolator; private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec private int DEFAULT_ESCAPE_ANIMATION_DURATION = 75; // ms @@ -74,13 +77,15 @@ public class SwipeHelper { public boolean mAllowSwipeTowardsEnd = true; private boolean mRtl; - public SwipeHelper(int swipeDirection, Callback callback, float densityScale, + public SwipeHelper(Context context, int swipeDirection, Callback callback, float densityScale, float pagingTouchSlop) { mCallback = callback; mSwipeDirection = swipeDirection; mVelocityTracker = VelocityTracker.obtain(); mDensityScale = densityScale; mPagingTouchSlop = pagingTouchSlop; + mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.linear_out_slow_in); } public void setDensityScale(float densityScale) { @@ -265,7 +270,7 @@ public class SwipeHelper { ValueAnimator anim = createTranslationAnimation(view, 0); int duration = SNAP_ANIM_LEN; anim.setDuration(duration); - anim.setInterpolator(RecentsConfiguration.getInstance().linearOutSlowInInterpolator); + anim.setInterpolator(mLinearOutSlowInInterpolator); anim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java index 1086160e07e7..7ce50d803ee2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java @@ -17,13 +17,19 @@ package com.android.systemui.recents.views; import android.app.Activity; +import android.content.Context; import android.view.View; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import com.android.systemui.R; +import com.android.systemui.recents.RecentsActivity; +import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; /** Manages the scrims for the various system bars. */ public class SystemBarScrimViews { + Context mContext; RecentsConfiguration mConfig; View mStatusBarScrimView; @@ -34,10 +40,22 @@ public class SystemBarScrimViews { boolean mHasStatusBarScrim; boolean mShouldAnimateNavBarScrim; - public SystemBarScrimViews(Activity activity, RecentsConfiguration config) { - mConfig = config; + int mNavBarScrimEnterDuration; + + Interpolator mFastOutSlowInInterpolator; + Interpolator mQuintOutInterpolator; + + public SystemBarScrimViews(Activity activity) { + mContext = activity; + mConfig = RecentsConfiguration.getInstance(); mStatusBarScrimView = activity.findViewById(R.id.status_bar_scrim); mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim); + mNavBarScrimEnterDuration = activity.getResources().getInteger( + R.integer.recents_nav_bar_scrim_enter_duration); + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(activity, + com.android.internal.R.interpolator.fast_out_slow_in); + mQuintOutInterpolator = AnimationUtils.loadInterpolator(activity, + com.android.internal.R.interpolator.decelerate_quint); } /** @@ -45,10 +63,11 @@ public class SystemBarScrimViews { * the first draw. */ public void prepareEnterRecentsAnimation() { - mHasNavBarScrim = mConfig.hasNavBarScrim(); - mShouldAnimateNavBarScrim = mConfig.shouldAnimateNavBarScrim(); - mHasStatusBarScrim = mConfig.hasStatusBarScrim(); - mShouldAnimateStatusBarScrim = mConfig.shouldAnimateStatusBarScrim(); + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + mHasNavBarScrim = launchState.hasNavBarScrim(); + mShouldAnimateNavBarScrim = launchState.shouldAnimateNavBarScrim(); + mHasStatusBarScrim = launchState.hasStatusBarScrim(); + mShouldAnimateStatusBarScrim = launchState.shouldAnimateStatusBarScrim(); mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ? View.VISIBLE : View.INVISIBLE); @@ -60,15 +79,21 @@ public class SystemBarScrimViews { * Starts animating the scrim views when entering Recents. */ public void startEnterRecentsAnimation() { + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + int transitionEnterFromAppDelay = mContext.getResources().getInteger( + R.integer.recents_enter_from_app_transition_duration); + int transitionEnterFromHomeDelay = mContext.getResources().getInteger( + R.integer.recents_enter_from_home_transition_duration); + if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) { mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight()); mStatusBarScrimView.animate() .translationY(0) - .setStartDelay(mConfig.launchedFromHome ? - mConfig.transitionEnterFromHomeDelay : - mConfig.transitionEnterFromAppDelay) - .setDuration(mConfig.navBarScrimEnterDuration) - .setInterpolator(mConfig.quintOutInterpolator) + .setStartDelay(launchState.launchedFromHome ? + transitionEnterFromHomeDelay : + transitionEnterFromAppDelay) + .setDuration(mNavBarScrimEnterDuration) + .setInterpolator(mQuintOutInterpolator) .withStartAction(new Runnable() { @Override public void run() { @@ -81,11 +106,11 @@ public class SystemBarScrimViews { mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight()); mNavBarScrimView.animate() .translationY(0) - .setStartDelay(mConfig.launchedFromHome ? - mConfig.transitionEnterFromHomeDelay : - mConfig.transitionEnterFromAppDelay) - .setDuration(mConfig.navBarScrimEnterDuration) - .setInterpolator(mConfig.quintOutInterpolator) + .setStartDelay(launchState.launchedFromHome ? + transitionEnterFromHomeDelay : + transitionEnterFromAppDelay) + .setDuration(mNavBarScrimEnterDuration) + .setInterpolator(mQuintOutInterpolator) .withStartAction(new Runnable() { @Override public void run() { @@ -101,20 +126,22 @@ public class SystemBarScrimViews { * going home). */ public void startExitRecentsAnimation() { + int taskViewExitToAppDuration = mContext.getResources().getInteger( + R.integer.recents_task_exit_to_app_duration); if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) { mStatusBarScrimView.animate() .translationY(-mStatusBarScrimView.getMeasuredHeight()) .setStartDelay(0) - .setDuration(mConfig.taskViewExitToAppDuration) - .setInterpolator(mConfig.fastOutSlowInInterpolator) + .setDuration(taskViewExitToAppDuration) + .setInterpolator(mFastOutSlowInInterpolator) .start(); } if (mHasNavBarScrim && mShouldAnimateNavBarScrim) { mNavBarScrimView.animate() .translationY(mNavBarScrimView.getMeasuredHeight()) .setStartDelay(0) - .setDuration(mConfig.taskViewExitToAppDuration) - .setInterpolator(mConfig.fastOutSlowInInterpolator) + .setDuration(taskViewExitToAppDuration) + .setInterpolator(mFastOutSlowInInterpolator) .start(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 8058c5e2e6ca..b5f29a01c2b0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -29,10 +29,10 @@ import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; - import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.recents.Constants; +import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; @@ -79,7 +79,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal ViewPool<TaskView, Task> mViewPool; ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<TaskViewTransform>(); DozeTrigger mUIDozeTrigger; - DebugOverlayView mDebugOverlay; DismissView mDismissAllButton; boolean mDismissAllButtonAnimating; int mFocusedTaskIndex = -1; @@ -118,14 +117,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Set the stack first setStack(stack); mConfig = RecentsConfiguration.getInstance(); - mViewPool = new ViewPool<TaskView, Task>(context, this); + mViewPool = new ViewPool<>(context, this); mInflater = LayoutInflater.from(context); - mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(mConfig); - mFilterAlgorithm = new TaskStackViewFilterAlgorithm(mConfig, this, mViewPool); - mStackScroller = new TaskStackViewScroller(context, mConfig, mLayoutAlgorithm); + mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(context, mConfig); + mFilterAlgorithm = new TaskStackViewFilterAlgorithm(this, mViewPool); + mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm); mStackScroller.setCallbacks(this); - mTouchHandler = new TaskStackViewTouchHandler(context, this, mConfig, mStackScroller); - mUIDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() { + mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller); + + int taskBarDismissDozeDelaySeconds = getResources().getInteger( + R.integer.recents_task_bar_dismiss_delay_seconds); + mUIDozeTrigger = new DozeTrigger(taskBarDismissDozeDelaySeconds, new Runnable() { @Override public void run() { // Show the task bar dismiss buttons @@ -161,11 +163,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return mStack; } - /** Sets the debug overlay */ - public void setDebugOverlay(DebugOverlayView overlay) { - mDebugOverlay = overlay; - } - /** Updates the list of task views */ void updateTaskViewsList() { mTaskViews.clear(); @@ -334,9 +331,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int[] visibleRange = mTmpVisibleRange; boolean isValidVisibleRange = updateStackTransforms(mCurrentTaskTransforms, tasks, stackScroll, visibleRange, false); - if (mDebugOverlay != null) { - mDebugOverlay.setText("vis[" + visibleRange[1] + "-" + visibleRange[0] + "]"); - } // Inflate and add the dismiss button if necessary if (Constants.DebugFlags.App.EnableDismissAll && mDismissAllButton == null) { @@ -740,8 +734,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int height = MeasureSpec.getSize(heightMeasureSpec); // Compute our stack/task rects - computeRects(width, height, mTaskStackBounds, mConfig.launchedWithAltTab, - mConfig.launchedFromHome); + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + computeRects(width, height, mTaskStackBounds, launchState.launchedWithAltTab, + launchState.launchedFromHome); // If this is the first layout, then scroll to the front of the stack and synchronize the // stack views immediately to load all the views @@ -773,9 +768,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Measure the dismiss button if (mDismissAllButton != null) { int taskRectWidth = mLayoutAlgorithm.mTaskRect.width(); + int dismissAllButtonHeight = getResources().getDimensionPixelSize( + R.dimen.recents_dismiss_all_button_size); mDismissAllButton.measure( MeasureSpec.makeMeasureSpec(taskRectWidth, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(mConfig.dismissAllButtonSizePx, MeasureSpec.EXACTLY)); + MeasureSpec.makeMeasureSpec(dismissAllButtonHeight, MeasureSpec.EXACTLY)); } setMeasuredDimension(width, height); @@ -856,20 +853,19 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // When Alt-Tabbing, focus the previous task (but leave the animation until we finish the // enter animation). - if (mConfig.launchedWithAltTab) { - if (mConfig.launchedFromAppWithThumbnail) { + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + if (launchState.launchedWithAltTab) { + if (launchState.launchedFromAppWithThumbnail) { focusTask(Math.max(0, mStack.getTaskCount() - 2), false, - mConfig.launchedHasConfigurationChanged); + launchState.launchedHasConfigurationChanged); } else { focusTask(Math.max(0, mStack.getTaskCount() - 1), false, - mConfig.launchedHasConfigurationChanged); + launchState.launchedHasConfigurationChanged); } } // Start dozing - if (!mConfig.multiWindowEnabled) { - mUIDozeTrigger.startDozing(); - } + mUIDozeTrigger.startDozing(); } /** Requests this task stacks to start it's enter-recents animation */ @@ -933,7 +929,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Start the focus animation when alt-tabbing ArrayList<Task> tasks = mStack.getTasks(); - if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged && + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + if (launchState.launchedWithAltTab && + !launchState.launchedHasConfigurationChanged && 0 <= mFocusedTaskIndex && mFocusedTaskIndex < tasks.size()) { TaskView tv = getChildViewForTask(tasks.get(mFocusedTaskIndex)); if (tv != null) { @@ -1124,7 +1122,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } // Update the min/max scroll and animate other task views into their new positions - updateMinMaxScroll(true, mConfig.launchedWithAltTab, mConfig.launchedFromHome); + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + updateMinMaxScroll(true, launchState.launchedWithAltTab, launchState.launchedFromHome); // Offset the stack by as much as the anchor task would otherwise move back if (pullStackForward) { @@ -1142,7 +1141,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView frontTv = getChildViewForTask(newFrontMostTask); if (frontTv != null) { frontTv.onTaskBound(newFrontMostTask); - frontTv.fadeInActionButton(0, mConfig.taskViewEnterFromAppDuration); + frontTv.fadeInActionButton(0, getResources().getInteger( + R.integer.recents_task_enter_from_app_duration)); } } @@ -1291,7 +1291,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal RecentsTaskLoader.getInstance().loadTaskData(task); // If the doze trigger has already fired, then update the state for this task view - if (mConfig.multiWindowEnabled || mUIDozeTrigger.hasTriggered()) { + if (mUIDozeTrigger.hasTriggered()) { tv.setNoUserInteractionState(); } @@ -1393,7 +1393,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (nextTv != null) { // Focus the next task, and only animate the visible state if we are launched // from Alt-Tab - nextTv.setFocusedTask(mConfig.launchedWithAltTab); + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + nextTv.setFocusedTask(launchState.launchedWithAltTab); } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java index 614ca53983ed..e9f6a46c9707 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java @@ -17,8 +17,8 @@ package com.android.systemui.recents.views; import com.android.systemui.recents.Constants; -import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.model.Task; +import com.android.systemui.R; import java.util.ArrayList; import java.util.HashMap; @@ -27,13 +27,10 @@ import java.util.List; /* The layout logic for a TaskStackView */ public class TaskStackViewFilterAlgorithm { - RecentsConfiguration mConfig; TaskStackView mStackView; ViewPool<TaskView, Task> mViewPool; - public TaskStackViewFilterAlgorithm(RecentsConfiguration config, TaskStackView stackView, - ViewPool<TaskView, Task> viewPool) { - mConfig = config; + public TaskStackViewFilterAlgorithm(TaskStackView stackView, ViewPool<TaskView, Task> viewPool) { mStackView = stackView; mViewPool = viewPool; } @@ -126,7 +123,8 @@ public class TaskStackViewFilterAlgorithm { } } } - return mConfig.filteringNewViewsAnimDuration; + return mStackView.getResources().getInteger( + R.integer.recents_filter_animate_new_views_duration); } /** @@ -172,7 +170,8 @@ public class TaskStackViewFilterAlgorithm { childViewTransformsOut.put(tv, toTransform); offset++; } - return mConfig.filteringCurrentViewsAnimDuration; + return mStackView.getResources().getInteger( + R.integer.recents_filter_animate_current_views_duration); } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java index f6df881121d7..7f4c0a5f7cb4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java @@ -16,11 +16,13 @@ package com.android.systemui.recents.views; +import android.content.Context; import android.graphics.Rect; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; +import com.android.systemui.R; import java.util.ArrayList; import java.util.HashMap; @@ -48,6 +50,7 @@ public class TaskStackViewLayoutAlgorithm { } } + Context mContext; RecentsConfiguration mConfig; // The various rects that define the stack view @@ -71,7 +74,8 @@ public class TaskStackViewLayoutAlgorithm { static float[] xp; static float[] px; - public TaskStackViewLayoutAlgorithm(RecentsConfiguration config) { + public TaskStackViewLayoutAlgorithm(Context context, RecentsConfiguration config) { + mContext = context; mConfig = config; // Precompute the path @@ -87,7 +91,8 @@ public class TaskStackViewLayoutAlgorithm { mStackVisibleRect.bottom = mViewRect.bottom; int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * mStackRect.width()); - int heightPadding = mConfig.taskStackTopPaddingPx; + int heightPadding = mContext.getResources().getDimensionPixelSize( + R.dimen.recents_stack_top_padding); mStackRect.inset(widthPadding, heightPadding); // Compute the task rect @@ -98,7 +103,8 @@ public class TaskStackViewLayoutAlgorithm { // Update the affiliation offsets float visibleTaskPct = 0.5f; - mWithinAffiliationOffset = mConfig.taskBarHeight; + mWithinAffiliationOffset = mContext.getResources().getDimensionPixelSize( + R.dimen.recents_task_bar_height); mBetweenAffiliationOffset = (int) (visibleTaskPct * mTaskRect.height()); } @@ -134,8 +140,10 @@ public class TaskStackViewLayoutAlgorithm { mStackRect.bottom)); float pDismissAllButtonOffset = 0f; if (Constants.DebugFlags.App.EnableDismissAll) { + int dismissAllButtonHeight = mContext.getResources().getDimensionPixelSize( + R.dimen.recents_dismiss_all_button_size); pDismissAllButtonOffset = pAtBottomOfStackRect - - screenYToCurveProgress(mStackVisibleRect.bottom - mConfig.dismissAllButtonSizePx); + screenYToCurveProgress(mStackVisibleRect.bottom - dismissAllButtonHeight); } // Update the task offsets @@ -177,6 +185,8 @@ public class TaskStackViewLayoutAlgorithm { // Walk backwards in the task stack and count the number of tasks and visible thumbnails int taskHeight = mTaskRect.height(); + int taskBarHeight = mContext.getResources().getDimensionPixelSize( + R.dimen.recents_task_bar_height); int numVisibleTasks = 1; int numVisibleThumbnails = 1; float progress = mTaskProgressMap.get(tasks.get(tasks.size() - 1).key) - mInitialScrollP; @@ -192,7 +202,7 @@ public class TaskStackViewLayoutAlgorithm { float scaleAtP = curveProgressToScale(progress); int scaleYOffsetAtP = (int) (((1f - scaleAtP) * taskHeight) / 2); int screenY = curveProgressToScreenY(progress) + scaleYOffsetAtP; - boolean hasVisibleThumbnail = (prevScreenY - screenY) > mConfig.taskBarHeight; + boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight; if (hasVisibleThumbnail) { numVisibleThumbnails++; numVisibleTasks++; @@ -251,8 +261,8 @@ public class TaskStackViewLayoutAlgorithm { } float scale = curveProgressToScale(pBounded); int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2); - int minZ = mConfig.taskViewTranslationZMinPx; - int maxZ = mConfig.taskViewTranslationZMaxPx; + int minZ = mContext.getResources().getDimensionPixelSize(R.dimen.recents_task_view_z_min); + int maxZ = mContext.getResources().getDimensionPixelSize(R.dimen.recents_task_view_z_max); transformOut.scale = scale; transformOut.translationY = curveProgressToScreenY(pBounded) - mStackVisibleRect.top - scaleYOffset; @@ -265,11 +275,9 @@ public class TaskStackViewLayoutAlgorithm { return transformOut; } - /** Returns the untransformed task view size. */ - public Rect getUntransformedTaskViewSize() { - Rect tvSize = new Rect(mTaskRect); - tvSize.offsetTo(0, 0); - return tvSize; + /** Returns the untransformed task view bounds. */ + public Rect getUntransformedTaskViewBounds() { + return new Rect(mTaskRect); } /** Returns the scroll to such task top = 1f; */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java index fabc86d7e53a..f0ae87f6f9ae 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java @@ -21,9 +21,11 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.widget.OverScroller; -import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.misc.Utilities; +import com.android.systemui.R; /* The scrolling logic for a TaskStackView */ public class TaskStackViewScroller { @@ -31,7 +33,7 @@ public class TaskStackViewScroller { public void onScrollChanged(float p); } - RecentsConfiguration mConfig; + Context mContext; TaskStackViewLayoutAlgorithm mLayoutAlgorithm; TaskStackViewScrollerCallbacks mCb; @@ -41,10 +43,14 @@ public class TaskStackViewScroller { ObjectAnimator mScrollAnimator; float mFinalAnimatedScroll; - public TaskStackViewScroller(Context context, RecentsConfiguration config, TaskStackViewLayoutAlgorithm layoutAlgorithm) { - mConfig = config; + Interpolator mLinearOutSlowInInterpolator; + + public TaskStackViewScroller(Context context, TaskStackViewLayoutAlgorithm layoutAlgorithm) { + mContext = context; mScroller = new OverScroller(context); mLayoutAlgorithm = layoutAlgorithm; + mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.linear_out_slow_in); setStackScroll(getStackScroll()); } @@ -140,8 +146,9 @@ public class TaskStackViewScroller { mFinalAnimatedScroll = newScroll; mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll); - mScrollAnimator.setDuration(mConfig.taskStackScrollDuration); - mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator); + mScrollAnimator.setDuration(mContext.getResources().getInteger( + R.integer.recents_animate_task_stack_scroll_duration)); + mScrollAnimator.setInterpolator(mLinearOutSlowInInterpolator); mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index 7d079d90fee5..86eced8a763d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -26,7 +26,7 @@ import android.view.ViewParent; import com.android.internal.logging.MetricsLogger; import com.android.systemui.recents.Constants; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.R; import java.util.List; @@ -34,7 +34,7 @@ import java.util.List; class TaskStackViewTouchHandler implements SwipeHelper.Callback { static int INACTIVE_POINTER_ID = -1; - RecentsConfiguration mConfig; + Context mContext; TaskStackView mSv; TaskStackViewScroller mScroller; VelocityTracker mVelocityTracker; @@ -62,7 +62,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { boolean mInterceptedBySwipeHelper; public TaskStackViewTouchHandler(Context context, TaskStackView sv, - RecentsConfiguration config, TaskStackViewScroller scroller) { + TaskStackViewScroller scroller) { + mContext = context; ViewConfiguration configuration = ViewConfiguration.get(context); mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); @@ -71,10 +72,9 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { mWindowTouchSlop = configuration.getScaledWindowTouchSlop(); mSv = sv; mScroller = scroller; - mConfig = config; float densityScale = context.getResources().getDisplayMetrics().density; - mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop); + mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale, mPagingTouchSlop); mSwipeHelper.setMinAlpha(1f); } @@ -268,7 +268,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { if (Float.compare(overScrollAmount, 0f) != 0) { // Bound the overscroll to a fixed amount, and inversely scale the y-movement // relative to how close we are to the max overscroll - float maxOverScroll = mConfig.taskStackOverscrollPct; + float maxOverScroll = mContext.getResources().getFloat( + R.dimen.recents_stack_overscroll_percentage); deltaP *= (1f - (Math.min(maxOverScroll, overScrollAmount) / maxOverScroll)); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 373fe7b60fd6..bbbaccf3fa5f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -20,16 +20,25 @@ import android.animation.Animator; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; -import android.graphics.*; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; import android.util.AttributeSet; -import android.view.accessibility.AccessibilityManager; import android.view.View; import android.view.ViewOutlineProvider; +import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateInterpolator; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.widget.FrameLayout; import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.recents.Constants; +import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; @@ -75,6 +84,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View mActionButtonView; TaskViewCallbacks mCb; + Interpolator mFastOutSlowInInterpolator; + Interpolator mFastOutLinearInInterpolator; + Interpolator mQuintOutInterpolator; + // Optimizations ValueAnimator.AnimatorUpdateListener mUpdateDimListener = new ValueAnimator.AnimatorUpdateListener() { @@ -99,14 +112,22 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); + Resources res = context.getResources(); mConfig = RecentsConfiguration.getInstance(); - mMaxDimScale = mConfig.taskStackMaxDim / 255f; + mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f; mClipViewInStack = true; - mViewBounds = new AnimateableViewBounds(this, mConfig.taskViewRoundedCornerRadiusPx); + mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize( + R.dimen.recents_task_view_rounded_corners_radius)); + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_slow_in); + mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_linear_in); + mQuintOutInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.decelerate_quint); setTaskProgress(getTaskProgress()); setDim(getDim()); if (mConfig.fakeShadows) { - setBackground(new FakeShadowDrawable(context.getResources(), mConfig)); + setBackground(new FakeShadowDrawable(res, mConfig)); } setOutlineProvider(mViewBounds); } @@ -159,6 +180,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, int widthWithoutPadding = width - mPaddingLeft - mPaddingRight; int heightWithoutPadding = height - mPaddingTop - mPaddingBottom; + int taskBarHeight = getResources().getDimensionPixelSize(R.dimen.recents_task_bar_height); // Measure the content mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), @@ -166,7 +188,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, // Measure the bar view, and action button mHeaderView.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(mConfig.taskBarHeight, MeasureSpec.EXACTLY)); + MeasureSpec.makeMeasureSpec(taskBarHeight, MeasureSpec.EXACTLY)); mActionButtonView.measure( MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.AT_MOST)); @@ -186,7 +208,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration, ValueAnimator.AnimatorUpdateListener updateCallback) { // Apply the transform - toTransform.applyToTaskView(this, duration, mConfig.fastOutSlowInInterpolator, false, + toTransform.applyToTaskView(this, duration, mFastOutSlowInInterpolator, false, !mConfig.fakeShadows, updateCallback); // Update the task progress @@ -238,10 +260,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, * first layout because the actual animation into recents may take a long time. */ void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean occludesLaunchTarget, int offscreenY) { + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); int initialDim = getDim(); - if (mConfig.launchedHasConfigurationChanged) { + if (launchState.launchedHasConfigurationChanged) { // Just load the views as-is - } else if (mConfig.launchedFromAppWithThumbnail) { + } else if (launchState.launchedFromAppWithThumbnail) { if (isTaskViewLaunchTargetTask) { // Set the dim to 0 so we can animate it in initialDim = 0; @@ -252,7 +275,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, setTranslationY(offscreenY); } - } else if (mConfig.launchedFromHome) { + } else if (launchState.launchedFromHome) { // Move the task view off screen (below) so we can animate it in setTranslationY(offscreenY); setTranslationZ(0); @@ -267,45 +290,59 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Animates this task view as it enters recents */ void startEnterRecentsAnimation(final ViewAnimation.TaskViewEnterContext ctx) { + RecentsActivityLaunchState launchState = mConfig.getLaunchState(); + Resources res = mContext.getResources(); final TaskViewTransform transform = ctx.currentTaskTransform; + final int transitionEnterFromAppDelay = res.getInteger( + R.integer.recents_enter_from_app_transition_duration); + final int transitionEnterFromHomeDelay = res.getInteger( + R.integer.recents_enter_from_home_transition_duration); + final int taskViewEnterFromAppDuration = res.getInteger( + R.integer.recents_task_enter_from_app_duration); + final int taskViewEnterFromHomeDuration = res.getInteger( + R.integer.recents_task_enter_from_home_duration); + final int taskViewEnterFromHomeStaggerDelay = res.getInteger( + R.integer.recents_task_enter_from_home_stagger_delay); + final int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize( + R.dimen.recents_task_view_affiliate_group_enter_offset); int startDelay = 0; - if (mConfig.launchedFromAppWithThumbnail) { + if (launchState.launchedFromAppWithThumbnail) { if (mTask.isLaunchTarget) { // Animate the dim/overlay if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) { // Animate the thumbnail alpha before the dim animation (to prevent updating the // hardware layer) - mThumbnailView.startEnterRecentsAnimation(mConfig.transitionEnterFromAppDelay, + mThumbnailView.startEnterRecentsAnimation(transitionEnterFromAppDelay, new Runnable() { @Override public void run() { - animateDimToProgress(0, mConfig.taskViewEnterFromAppDuration, + animateDimToProgress(0, taskViewEnterFromAppDuration, ctx.postAnimationTrigger.decrementOnAnimationEnd()); } }); } else { // Immediately start the dim animation - animateDimToProgress(mConfig.transitionEnterFromAppDelay, - mConfig.taskViewEnterFromAppDuration, + animateDimToProgress(transitionEnterFromAppDelay, + taskViewEnterFromAppDuration, ctx.postAnimationTrigger.decrementOnAnimationEnd()); } ctx.postAnimationTrigger.increment(); // Animate the action button in - fadeInActionButton(mConfig.transitionEnterFromAppDelay, - mConfig.taskViewEnterFromAppDuration); + fadeInActionButton(transitionEnterFromAppDelay, + taskViewEnterFromAppDuration); } else { // Animate the task up if it was occluding the launch target if (ctx.currentTaskOccludesLaunchTarget) { - setTranslationY(transform.translationY + mConfig.taskViewAffiliateGroupEnterOffsetPx); + setTranslationY(transform.translationY + taskViewAffiliateGroupEnterOffset); setAlpha(0f); animate().alpha(1f) .translationY(transform.translationY) - .setStartDelay(mConfig.transitionEnterFromAppDelay) + .setStartDelay(transitionEnterFromAppDelay) .setUpdateListener(null) - .setInterpolator(mConfig.fastOutSlowInInterpolator) - .setDuration(mConfig.taskViewEnterFromHomeDuration) + .setInterpolator(mFastOutSlowInInterpolator) + .setDuration(taskViewEnterFromHomeDuration) .withEndAction(new Runnable() { @Override public void run() { @@ -317,13 +354,13 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, ctx.postAnimationTrigger.increment(); } } - startDelay = mConfig.transitionEnterFromAppDelay; + startDelay = transitionEnterFromAppDelay; - } else if (mConfig.launchedFromHome) { + } else if (launchState.launchedFromHome) { // Animate the tasks up int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1); - int delay = mConfig.transitionEnterFromHomeDelay + - frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay; + int delay = transitionEnterFromHomeDelay + + frontIndex * taskViewEnterFromHomeStaggerDelay; setScaleX(transform.scale); setScaleY(transform.scale); @@ -334,9 +371,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, .translationY(transform.translationY) .setStartDelay(delay) .setUpdateListener(ctx.updateListener) - .setInterpolator(mConfig.quintOutInterpolator) - .setDuration(mConfig.taskViewEnterFromHomeDuration + - frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay) + .setInterpolator(mQuintOutInterpolator) + .setDuration(taskViewEnterFromHomeDuration + + frontIndex * taskViewEnterFromHomeStaggerDelay) .withEndAction(new Runnable() { @Override public void run() { @@ -373,12 +410,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Animates this task view as it leaves recents by pressing home. */ void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { + int taskViewExitToHomeDuration = getResources().getInteger( + R.integer.recents_task_exit_to_home_duration); animate() .translationY(ctx.offscreenTranslationY) .setStartDelay(0) .setUpdateListener(null) - .setInterpolator(mConfig.fastOutLinearInInterpolator) - .setDuration(mConfig.taskViewExitToHomeDuration) + .setInterpolator(mFastOutLinearInInterpolator) + .setDuration(taskViewExitToHomeDuration) .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable()) .start(); ctx.postAnimationTrigger.increment(); @@ -392,6 +431,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Animates this task view as it exits recents */ void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask, boolean occludesLaunchTarget, boolean lockToTask) { + final int taskViewExitToAppDuration = mContext.getResources().getInteger( + R.integer.recents_task_exit_to_app_duration); + final int taskViewAffiliateGroupEnterOffset = mContext.getResources().getDimensionPixelSize( + R.dimen.recents_task_view_affiliate_group_enter_offset); + if (isLaunchingTask) { // Animate the thumbnail alpha back into full opacity for the window animation out mThumbnailView.startLaunchTaskAnimation(postAnimRunnable); @@ -399,8 +443,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, // Animate the dim if (mDimAlpha > 0) { ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0); - anim.setDuration(mConfig.taskViewExitToAppDuration); - anim.setInterpolator(mConfig.fastOutLinearInInterpolator); + anim.setDuration(taskViewExitToAppDuration); + anim.setInterpolator(mFastOutLinearInInterpolator); anim.start(); } @@ -414,8 +458,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mActionButtonView.animate() .alpha(0f) .setStartDelay(0) - .setDuration(mConfig.taskViewExitToAppDuration) - .setInterpolator(mConfig.fastOutLinearInInterpolator) + .setDuration(taskViewExitToAppDuration) + .setInterpolator(mFastOutLinearInInterpolator) .start(); } else { // Hide the dismiss button @@ -424,11 +468,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, // animate it away first if (occludesLaunchTarget) { animate().alpha(0f) - .translationY(getTranslationY() + mConfig.taskViewAffiliateGroupEnterOffsetPx) + .translationY(getTranslationY() + taskViewAffiliateGroupEnterOffset) .setStartDelay(0) .setUpdateListener(null) - .setInterpolator(mConfig.fastOutLinearInInterpolator) - .setDuration(mConfig.taskViewExitToAppDuration) + .setInterpolator(mFastOutLinearInInterpolator) + .setDuration(taskViewExitToAppDuration) .start(); } } @@ -436,15 +480,20 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Animates the deletion of this task view */ void startDeleteTaskAnimation(final Runnable r, int delay) { + int taskViewRemoveAnimDuration = getResources().getInteger( + R.integer.recents_animate_task_view_remove_duration); + int taskViewRemoveAnimTranslationXPx = getResources().getDimensionPixelSize( + R.dimen.recents_task_view_remove_anim_translation_x); + // Disabling clipping with the stack while the view is animating away setClipViewInStack(false); - animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx) + animate().translationX(taskViewRemoveAnimTranslationXPx) .alpha(0f) .setStartDelay(delay) .setUpdateListener(null) - .setInterpolator(mConfig.fastOutSlowInInterpolator) - .setDuration(mConfig.taskViewRemoveAnimDuration) + .setInterpolator(mFastOutSlowInInterpolator) + .setDuration(taskViewRemoveAnimDuration) .withEndAction(new Runnable() { @Override public void run() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java index 3e9410e1348a..f68dd64b0bf2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -26,19 +26,21 @@ import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.GradientDrawable; -import android.graphics.drawable.RippleDrawable; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.RippleDrawable; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -67,6 +69,8 @@ public class TaskViewHeader extends FrameLayout { boolean mCurrentPrimaryColorIsDark; int mCurrentPrimaryColor; int mBackgroundColor; + int mCornerRadius; + int mHighlightHeight; Drawable mLightDismissDrawable; Drawable mDarkDismissDrawable; RippleDrawable mBackground; @@ -81,6 +85,9 @@ public class TaskViewHeader extends FrameLayout { Paint mDimLayerPaint = new Paint(); PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); + Interpolator mFastOutSlowInInterpolator; + Interpolator mFastOutLinearInInterpolator; + boolean mLayersDisabled; public TaskViewHeader(Context context) { @@ -113,13 +120,21 @@ public class TaskViewHeader extends FrameLayout { mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark); mDismissContentDescription = context.getString(R.string.accessibility_recents_item_will_be_dismissed); + mCornerRadius = getResources().getDimensionPixelSize( + R.dimen.recents_task_view_rounded_corners_radius); + mHighlightHeight = getResources().getDimensionPixelSize( + R.dimen.recents_task_view_highlight); + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_slow_in); + mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_linear_in); // Configure the highlight paint if (sHighlightPaint == null) { sHighlightPaint = new Paint(); sHighlightPaint.setStyle(Paint.Style.STROKE); - sHighlightPaint.setStrokeWidth(mConfig.taskViewHighlightPx); - sHighlightPaint.setColor(mConfig.taskBarViewHighlightColor); + sHighlightPaint.setStrokeWidth(mHighlightHeight); + sHighlightPaint.setColor(context.getColor(R.color.recents_task_bar_highlight_color)); sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); sHighlightPaint.setAntiAlias(true); } @@ -154,8 +169,8 @@ public class TaskViewHeader extends FrameLayout { @Override protected void onDraw(Canvas canvas) { // Draw the highlight at the top edge (but put the bottom edge just out of view) - float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f); - float radius = mConfig.taskViewRoundedCornerRadiusPx; + float offset = (float) Math.ceil(mHighlightHeight / 2f); + float radius = mCornerRadius; int count = canvas.save(Canvas.CLIP_SAVE_FLAG); canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset, @@ -207,10 +222,15 @@ public class TaskViewHeader extends FrameLayout { mBackgroundColorDrawable.setColor(t.colorPrimary); mBackgroundColor = t.colorPrimary; } + + int taskBarViewLightTextColor = getResources().getColor( + R.color.recents_task_bar_light_text_color); + int taskBarViewDarkTextColor = getResources().getColor( + R.color.recents_task_bar_dark_text_color); mCurrentPrimaryColor = t.colorPrimary; mCurrentPrimaryColorIsDark = t.useLightOnPrimaryColor; mActivityDescription.setTextColor(t.useLightOnPrimaryColor ? - mConfig.taskBarViewLightTextColor : mConfig.taskBarViewDarkTextColor); + taskBarViewLightTextColor : taskBarViewDarkTextColor); mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ? mLightDismissDrawable : mDarkDismissDrawable); mDismissButton.setContentDescription(String.format(mDismissContentDescription, @@ -262,12 +282,14 @@ public class TaskViewHeader extends FrameLayout { /** Animates this task bar dismiss button when launching a task. */ void startLaunchTaskDismissAnimation() { if (mDismissButton.getVisibility() == View.VISIBLE) { + int taskViewExitToAppDuration = mContext.getResources().getInteger( + R.integer.recents_task_exit_to_app_duration); mDismissButton.animate().cancel(); mDismissButton.animate() .alpha(0f) .setStartDelay(0) - .setInterpolator(mConfig.fastOutSlowInInterpolator) - .setDuration(mConfig.taskViewExitToAppDuration) + .setInterpolator(mFastOutSlowInInterpolator) + .setDuration(taskViewExitToAppDuration) .start(); } } @@ -280,8 +302,9 @@ public class TaskViewHeader extends FrameLayout { mDismissButton.animate() .alpha(1f) .setStartDelay(0) - .setInterpolator(mConfig.fastOutLinearInInterpolator) - .setDuration(mConfig.taskViewEnterFromAppDuration) + .setInterpolator(mFastOutLinearInInterpolator) + .setDuration(getResources().getInteger( + R.integer.recents_task_enter_from_app_duration)) .start(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java index 117a7d328692..6c83beeff1da 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -32,9 +32,11 @@ import android.graphics.RectF; import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; -import com.android.systemui.recents.RecentsConfiguration; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; +import com.android.systemui.R; /** @@ -43,9 +45,8 @@ import com.android.systemui.recents.model.Task; */ public class TaskViewThumbnail extends View { - RecentsConfiguration mConfig; - // Drawing + int mCornerRadius; float mDimAlpha; Matrix mScaleMatrix = new Matrix(); Paint mDrawPaint = new Paint(); @@ -54,6 +55,8 @@ public class TaskViewThumbnail extends View { BitmapShader mBitmapShader; LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0); + Interpolator mFastOutSlowInInterpolator; + // Thumbnail alpha float mThumbnailAlpha; ValueAnimator mThumbnailAlphaAnimator; @@ -89,15 +92,18 @@ public class TaskViewThumbnail extends View { public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mConfig = RecentsConfiguration.getInstance(); mDrawPaint.setColorFilter(mLightingColorFilter); mDrawPaint.setFilterBitmap(true); mDrawPaint.setAntiAlias(true); + mCornerRadius = getResources().getDimensionPixelSize( + R.dimen.recents_task_view_rounded_corners_radius); + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_slow_in); } @Override protected void onFinishInflate() { - mThumbnailAlpha = mConfig.taskViewThumbnailAlpha; + mThumbnailAlpha = getResources().getFloat(R.dimen.recents_task_view_thumbnail_alpha); updateThumbnailPaintFilter(); } @@ -117,8 +123,8 @@ public class TaskViewThumbnail extends View { } // Draw the thumbnail with the rounded corners canvas.drawRoundRect(0, 0, getWidth(), getHeight(), - mConfig.taskViewRoundedCornerRadiusPx, - mConfig.taskViewRoundedCornerRadiusPx, mDrawPaint); + mCornerRadius, + mCornerRadius, mDrawPaint); } /** Sets the thumbnail to a given bitmap. */ @@ -215,8 +221,10 @@ public class TaskViewThumbnail extends View { startFadeAnimation(1f, 0, 150, null); } } else { - if (Float.compare(getAlpha(), mConfig.taskViewThumbnailAlpha) != 0) { - startFadeAnimation(mConfig.taskViewThumbnailAlpha, 0, 150, null); + float taskViewThumbnailAlpha = getResources().getFloat( + R.dimen.recents_task_view_thumbnail_alpha); + if (Float.compare(getAlpha(), taskViewThumbnailAlpha) != 0) { + startFadeAnimation(taskViewThumbnailAlpha, 0, 150, null); } } } @@ -229,20 +237,26 @@ public class TaskViewThumbnail extends View { if (isTaskViewLaunchTargetTask) { mThumbnailAlpha = 1f; } else { - mThumbnailAlpha = mConfig.taskViewThumbnailAlpha; + mThumbnailAlpha = getResources().getFloat( + R.dimen.recents_task_view_thumbnail_alpha); } updateThumbnailPaintFilter(); } /** Animates this task thumbnail as it enters Recents. */ void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) { - startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay, - mConfig.taskViewEnterFromAppDuration, postAnimRunnable); + float taskViewThumbnailAlpha = getResources().getFloat( + R.dimen.recents_task_view_thumbnail_alpha); + startFadeAnimation(taskViewThumbnailAlpha, delay, + getResources().getInteger(R.integer.recents_task_enter_from_app_duration), + postAnimRunnable); } /** Animates this task thumbnail as it exits Recents. */ void startLaunchTaskAnimation(Runnable postAnimRunnable) { - startFadeAnimation(1f, 0, mConfig.taskViewExitToAppDuration, postAnimRunnable); + int taskViewExitToAppDuration = mContext.getResources().getInteger( + R.integer.recents_task_exit_to_app_duration); + startFadeAnimation(1f, 0, taskViewExitToAppDuration, postAnimRunnable); } /** Starts a new thumbnail alpha animation. */ @@ -251,7 +265,7 @@ public class TaskViewThumbnail extends View { mThumbnailAlphaAnimator = ValueAnimator.ofFloat(mThumbnailAlpha, finalAlpha); mThumbnailAlphaAnimator.setStartDelay(delay); mThumbnailAlphaAnimator.setDuration(duration); - mThumbnailAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); + mThumbnailAlphaAnimator.setInterpolator(mFastOutSlowInInterpolator); mThumbnailAlphaAnimator.addUpdateListener(mThumbnailAlphaUpdateListener); if (postAnimRunnable != null) { mThumbnailAlphaAnimator.addListener(new AnimatorListenerAdapter() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index b01a2a8a2c2f..10d4a965852f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -112,7 +112,7 @@ public class CommandQueue extends IStatusBar.Stub { public void appTransitionStarting(long startTime, long duration); public void showAssistDisclosure(); public void startAssist(Bundle args); - public void onCameraLaunchGestureDetected(); + public void onCameraLaunchGestureDetected(int source); } public CommandQueue(Callbacks callbacks, StatusBarIconList list) { @@ -306,10 +306,10 @@ public class CommandQueue extends IStatusBar.Stub { } @Override - public void onCameraLaunchGestureDetected() { + public void onCameraLaunchGestureDetected(int source) { synchronized (mList) { mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE); - mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE).sendToTarget(); + mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget(); } } @@ -415,7 +415,7 @@ public class CommandQueue extends IStatusBar.Stub { mCallbacks.startAssist((Bundle) msg.obj); break; case MSG_CAMERA_LAUNCH_GESTURE: - mCallbacks.onCameraLaunchGestureDetected(); + mCallbacks.onCameraLaunchGestureDetected(msg.arg1); break; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java index d9127952a329..687f6c1b0922 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java @@ -130,7 +130,7 @@ public class DragDownHelper implements Gefingerpoken { } return true; case MotionEvent.ACTION_UP: - if (mDraggedFarEnough && mDragDownCallback.onDraggedDown(mStartingChild, + if (!isFalseTouch() && mDragDownCallback.onDraggedDown(mStartingChild, (int) (y - mInitialTouchY))) { if (mStartingChild == null) { mDragDownCallback.setEmptyDragAmount(0f); @@ -148,6 +148,13 @@ public class DragDownHelper implements Gefingerpoken { return false; } + private boolean isFalseTouch() { + if (mFalsingManager.isClassiferEnabled()) { + return mFalsingManager.isFalseTouch(); + } + return !mDraggedFarEnough; + } + private void captureStartingChild(float x, float y) { if (mStartingChild == null) { mStartingChild = findView(x, y); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index ac4dee28e3e4..5e6fdd05a87a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -187,32 +187,41 @@ public class KeyguardIndicationController { } // Try fetching charging time from battery stats. + long chargingTimeRemaining = 0; try { - long chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining(); - if (chargingTimeRemaining > 0) { - String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes( - mContext, chargingTimeRemaining); - return mContext.getResources().getString( - R.string.keyguard_indication_charging_time, chargingTimeFormatted); - } + chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining(); + } catch (RemoteException e) { Log.e(TAG, "Error calling IBatteryStats: ", e); } + final boolean hasChargingTime = chargingTimeRemaining > 0; - // Fall back to simple charging label. int chargingId; switch (mChargingSpeed) { case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST: - chargingId = R.string.keyguard_plugged_in_charging_fast; + chargingId = hasChargingTime + ? R.string.keyguard_indication_charging_time_fast_if_translated + : R.string.keyguard_plugged_in_charging_fast; break; case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY: - chargingId = R.string.keyguard_plugged_in_charging_slowly; + chargingId = hasChargingTime + ? R.string.keyguard_indication_charging_time_slowly_if_translated + : R.string.keyguard_plugged_in_charging_slowly; break; default: - chargingId = R.string.keyguard_plugged_in; + chargingId = hasChargingTime + ? R.string.keyguard_indication_charging_time + : R.string.keyguard_plugged_in; break; } - return mContext.getResources().getString(chargingId); + + if (hasChargingTime) { + String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes( + mContext, chargingTimeRemaining); + return mContext.getResources().getString(chargingId, chargingTimeFormatted); + } else { + return mContext.getResources().getString(chargingId); + } } KeyguardUpdateMonitorCallback mUpdateMonitor = new KeyguardUpdateMonitorCallback() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java index 60ebfdf639ef..41adeb587736 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java @@ -28,6 +28,7 @@ import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.KeyguardAffordanceView; @@ -62,6 +63,7 @@ public class KeyguardAffordanceHelper { private Interpolator mAppearInterpolator; private Interpolator mDisappearInterpolator; private Animator mSwipeAnimator; + private FalsingManager mFalsingManager; private int mMinBackgroundRadius; private boolean mMotionCancelled; private int mTouchTargetSize; @@ -109,6 +111,7 @@ public class KeyguardAffordanceHelper { android.R.interpolator.linear_out_slow_in); mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.fast_out_linear_in); + mFalsingManager = FalsingManager.getInstance(mContext); } private void initIcons() { @@ -322,7 +325,12 @@ public class KeyguardAffordanceHelper { float vel = getCurrentVelocity(lastX, lastY); // We snap back if the current translation is not far enough - boolean snapBack = isBelowFalsingThreshold(); + boolean snapBack; + if (mFalsingManager.isFalseTouch()) { + snapBack = mFalsingManager.isFalseTouch(); + } else { + snapBack = isBelowFalsingThreshold(); + } // or if the velocity is in the opposite direction. boolean velIsInWrongDirection = vel * mTranslation < 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 012dc9c53207..14176a6f5b3c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -77,6 +77,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView"; + public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance"; + public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture"; + public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap"; + + public static final String EXTRA_CAMERA_LAUNCH_SOURCE + = "com.android.systemui.camera_launch_source"; + private static final Intent SECURE_CAMERA_INTENT = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE) .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); @@ -170,7 +177,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); return true; } else if (host == mCameraImageView) { - launchCamera(); + launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE); return true; } else if (host == mLeftAffordanceView) { launchLeftAffordance(); @@ -349,7 +356,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void onClick(View v) { if (v == mCameraImageView) { - launchCamera(); + launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE); } else if (v == mLeftAffordanceView) { launchLeftAffordance(); } if (v == mLockIcon) { @@ -417,8 +424,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } } - public void launchCamera() { + public void launchCamera(String source) { final Intent intent = getCameraIntent(); + intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source); boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity( mContext, intent, KeyguardUpdateMonitor.getCurrentUser()); if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index e70d146119f4..71267cd7c582 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -81,7 +81,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener } private void registerListener() { - if (UserSwitcherController.isUserSwitcherAvailable(mUserManager) && mUserListener == null) { + if (mUserManager.isUserSwitcherEnabled() && mUserListener == null) { final UserSwitcherController controller = mUserSwitcherController; if (controller != null) { @@ -103,7 +103,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener @Override public void onClick(View v) { - if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)) { + if (mUserManager.isUserSwitcherEnabled()) { if (mKeyguardMode) { if (mKeyguardUserSwitcher != null) { mKeyguardUserSwitcher.show(true /* animate */); @@ -135,14 +135,14 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener private void refreshContentDescription() { String currentUser = null; - if (UserSwitcherController.isUserSwitcherAvailable(mUserManager) + if (mUserManager.isUserSwitcherEnabled() && mUserSwitcherController != null) { currentUser = mUserSwitcherController.getCurrentUserName(mContext); } String text = null; if (isClickable()) { - if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)) { + if (mUserManager.isUserSwitcherEnabled()) { if (TextUtils.isEmpty(currentUser)) { text = mContext.getString(R.string.accessibility_multi_user_switch_switcher); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 980527b82666..08353cbb51c3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -22,6 +22,7 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.app.ActivityManager; +import android.app.StatusBarManager; import android.content.Context; import android.content.pm.ResolveInfo; import android.content.res.Configuration; @@ -204,6 +205,7 @@ public class NotificationPanelView extends PanelView implements private boolean mHeadsUpAnimatingAway; private boolean mLaunchingAffordance; private FalsingManager mFalsingManager; + private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() { @Override @@ -480,6 +482,7 @@ public class NotificationPanelView extends PanelView implements mUnlockIconActive = false; if (!mLaunchingAffordance) { mAfforanceHelper.reset(false); + mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; } closeQs(); mStatusBar.dismissPopups(); @@ -692,7 +695,7 @@ public class NotificationPanelView extends PanelView implements } private boolean flingExpandsQs(float vel) { - if (isBelowFalsingThreshold()) { + if (isFalseTouch()) { return false; } if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) { @@ -702,8 +705,14 @@ public class NotificationPanelView extends PanelView implements } } - private boolean isBelowFalsingThreshold() { - return !mQsTouchAboveFalsingThreshold && mStatusBarState == StatusBarState.KEYGUARD; + private boolean isFalseTouch() { + if (mStatusBarState != StatusBarState.KEYGUARD) { + return false; + } + if (mFalsingManager.isClassiferEnabled()) { + return mFalsingManager.isFalseTouch(); + } + return !mQsTouchAboveFalsingThreshold; } private float getQsExpansionFraction() { @@ -1428,7 +1437,7 @@ public class NotificationPanelView extends PanelView implements } return; } - boolean belowFalsingThreshold = isBelowFalsingThreshold(); + boolean belowFalsingThreshold = isFalseTouch(); if (belowFalsingThreshold) { vel = 0; } @@ -1965,20 +1974,23 @@ public class NotificationPanelView extends PanelView implements mKeyguardBottomArea.launchLeftAffordance(); } } else { - EventLogTags.writeSysuiLockscreenGesture( - EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp); - + if (KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE.equals( + mLastCameraLaunchSource)) { + EventLogTags.writeSysuiLockscreenGesture( + EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, + lengthDp, velocityDp); + } mFalsingManager.onCameraOn(); if (mFalsingManager.shouldEnforceBouncer()) { mStatusBar.executeRunnableDismissingKeyguard(new Runnable() { @Override public void run() { - mKeyguardBottomArea.launchCamera(); + mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource); } }, null, true /* dismissShade */, false /* afterKeyguardGone */); } else { - mKeyguardBottomArea.launchCamera(); + mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource); } } mStatusBar.startLaunchTransitionTimeout(); @@ -2419,7 +2431,17 @@ public class NotificationPanelView extends PanelView implements return !mDozing; } - public void launchCamera(boolean animate) { + public void launchCamera(boolean animate, int source) { + if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) { + mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP; + } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) { + mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE; + } else { + + // Default. + mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; + } + // If we are launching it when we are occluded already we don't want it to animate, // nor setting these flags, since the occluded state doesn't change anymore, hence it's // never reset. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 13d0e1e0fbc3..bd16257e6ece 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -610,8 +610,8 @@ public abstract class PanelView extends FrameLayout { if (!mStatusBar.isFalsingThresholdNeeded()) { return false; } - if (mFalsingManager.isFalseTouch(Classifier.UNLOCK)) { - return true; + if (mFalsingManager.isClassiferEnabled()) { + return mFalsingManager.isFalseTouch(); } if (!mTouchAboveFalsingThreshold) { return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 151fa3c5a033..37edc28b765d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -492,6 +492,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private ExpandableNotificationRow mDraggedDownRow; private boolean mLaunchCameraOnScreenTurningOn; private boolean mLaunchCameraOnFinishedGoingToSleep; + private int mLastCameraLaunchSource; private PowerManager.WakeLock mGestureWakeLock; private Vibrator mVibrator; @@ -881,7 +882,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardBottomArea.setAccessibilityController(mAccessibilityController); mNextAlarmController = new NextAlarmController(mContext); mKeyguardMonitor = new KeyguardMonitor(mContext); - if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) { + if (UserManager.get(mContext).isUserSwitcherEnabled()) { mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor, mHandler); if (mUserSwitcherController.useFullscreenUserSwitcher()) { @@ -903,8 +904,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mBluetoothController, mLocationController, mRotationLockController, mNetworkController, mZenModeController, mHotspotController, mCastController, mFlashlightController, - mUserSwitcherController, mKeyguardMonitor, - mSecurityController); + mUserSwitcherController, mUserInfoController, mKeyguardMonitor, + mSecurityController, mBatteryController); mQSPanel.setHost(qsh); mQSPanel.setTiles(qsh.getTiles()); mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow); @@ -3000,6 +3001,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone); } + public void dismissKeyguard() { + mStatusBarKeyguardViewManager.dismiss(); + } + private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction, boolean afterKeyguardGone) { if (mStatusBarKeyguardViewManager.isShowing()) { @@ -3992,7 +3997,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mHandler.post(new Runnable() { @Override public void run() { - onCameraLaunchGestureDetected(); + onCameraLaunchGestureDetected(mLastCameraLaunchSource); } }); } @@ -4010,7 +4015,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mFalsingManager.onScreenTurningOn(); mNotificationPanel.onScreenTurningOn(); if (mLaunchCameraOnScreenTurningOn) { - mNotificationPanel.launchCamera(false); + mNotificationPanel.launchCamera(false, mLastCameraLaunchSource); mLaunchCameraOnScreenTurningOn = false; } } @@ -4175,7 +4180,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void onCameraLaunchGestureDetected() { + public void onCameraLaunchGestureDetected(int source) { + mLastCameraLaunchSource = source; if (mStartedGoingToSleep) { mLaunchCameraOnFinishedGoingToSleep = true; return; @@ -4201,7 +4207,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); } if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) { - mNotificationPanel.launchCamera(mDeviceInteractive /* animate */); + mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source); } else { // We need to defer the camera launch until the screen comes on, since otherwise // we will dismiss us too early since we are waiting on an activity to be drawn and diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 385c5d5bb736..6ec94946d2e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -26,34 +26,8 @@ import android.util.Log; import com.android.systemui.R; import com.android.systemui.qs.QSTile; -import com.android.systemui.qs.tiles.AirplaneModeTile; -import com.android.systemui.qs.tiles.BluetoothTile; -import com.android.systemui.qs.tiles.CastTile; -import com.android.systemui.qs.tiles.CellularTile; -import com.android.systemui.qs.tiles.ColorInversionTile; -import com.android.systemui.qs.tiles.DndTile; -import com.android.systemui.qs.tiles.FlashlightTile; -import com.android.systemui.qs.tiles.HotspotTile; -import com.android.systemui.qs.tiles.IntentTile; -import com.android.systemui.qs.tiles.LocationTile; -import com.android.systemui.qs.tiles.QAirplaneTile; -import com.android.systemui.qs.tiles.QBluetoothTile; -import com.android.systemui.qs.tiles.QFlashlightTile; -import com.android.systemui.qs.tiles.QRotationLockTile; -import com.android.systemui.qs.tiles.QWifiTile; -import com.android.systemui.qs.tiles.RotationLockTile; -import com.android.systemui.qs.tiles.WifiTile; -import com.android.systemui.statusbar.policy.BluetoothController; -import com.android.systemui.statusbar.policy.CastController; -import com.android.systemui.statusbar.policy.FlashlightController; -import com.android.systemui.statusbar.policy.HotspotController; -import com.android.systemui.statusbar.policy.KeyguardMonitor; -import com.android.systemui.statusbar.policy.LocationController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RotationLockController; -import com.android.systemui.statusbar.policy.SecurityController; -import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.qs.tiles.*; +import com.android.systemui.statusbar.policy.*; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; @@ -85,8 +59,10 @@ public class QSTileHost implements QSTile.Host, Tunable { private final Looper mLooper; private final FlashlightController mFlashlight; private final UserSwitcherController mUserSwitcherController; + private final UserInfoController mUserInfoController; private final KeyguardMonitor mKeyguard; private final SecurityController mSecurity; + private final BatteryController mBattery; private Callback mCallback; @@ -95,8 +71,8 @@ public class QSTileHost implements QSTile.Host, Tunable { RotationLockController rotation, NetworkController network, ZenModeController zen, HotspotController hotspot, CastController cast, FlashlightController flashlight, - UserSwitcherController userSwitcher, KeyguardMonitor keyguard, - SecurityController security) { + UserSwitcherController userSwitcher, UserInfoController userInfo, KeyguardMonitor keyguard, + SecurityController security, BatteryController battery) { mContext = context; mStatusBar = statusBar; mBluetooth = bluetooth; @@ -108,8 +84,10 @@ public class QSTileHost implements QSTile.Host, Tunable { mCast = cast; mFlashlight = flashlight; mUserSwitcherController = userSwitcher; + mUserInfoController = userInfo; mKeyguard = keyguard; mSecurity = security; + mBattery = battery; final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(), Process.THREAD_PRIORITY_BACKGROUND); @@ -203,10 +181,21 @@ public class QSTileHost implements QSTile.Host, Tunable { return mKeyguard; } + @Override public UserSwitcherController getUserSwitcherController() { return mUserSwitcherController; } + @Override + public UserInfoController getUserInfoController() { + return mUserInfoController; + } + + @Override + public BatteryController getBatteryController() { + return mBattery; + } + public SecurityController getSecurityController() { return mSecurity; } @@ -259,6 +248,8 @@ public class QSTileHost implements QSTile.Host, Tunable { else if (tileSpec.equals("location")) return new LocationTile(this); else if (tileSpec.equals("cast")) return new CastTile(this); else if (tileSpec.equals("hotspot")) return new HotspotTile(this); + else if (tileSpec.equals("user")) return new UserTile(this); + else if (tileSpec.equals("battery")) return new BatteryTile(this); // Detail only versions of wifi and bluetooth. else if (tileSpec.equals("dwifi")) return new WifiTile(this, true); else if (tileSpec.equals("dbt")) return new BluetoothTile(this, true); @@ -268,6 +259,7 @@ public class QSTileHost implements QSTile.Host, Tunable { else if (tileSpec.equals("qairplane")) return new QAirplaneTile(this); else if (tileSpec.equals("qrotation")) return new QRotationLockTile(this); else if (tileSpec.equals("qflashlight")) return new QFlashlightTile(this); + else if (tileSpec.equals("qlock")) return new QLockTile(this); // Intent tiles. else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec); else throw new IllegalArgumentException("Bad tile spec: " + tileSpec); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 394ff3f8245c..05f6e57d9199 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -466,7 +466,7 @@ public class StatusBarKeyguardViewManager { KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) { - updateMonitor.sendKeyguardVisibilityChanged(showing && !occluded); + updateMonitor.onKeyguardVisibilityChanged(showing && !occluded); } if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { updateMonitor.sendKeyguardBouncerChanged(bouncerShowing); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index d1b69aba6528..5071df0dee48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.BatteryManager; +import android.os.Handler; import android.os.PowerManager; import android.util.Log; @@ -30,24 +31,31 @@ import java.util.ArrayList; public class BatteryController extends BroadcastReceiver { private static final String TAG = "BatteryController"; + + public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>(); private final PowerManager mPowerManager; + private final Handler mHandler; private int mLevel; private boolean mPluggedIn; private boolean mCharging; private boolean mCharged; private boolean mPowerSave; + private boolean mTestmode = false; public BatteryController(Context context) { + mHandler = new Handler(); mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING); + filter.addAction(ACTION_LEVEL_TEST); context.registerReceiver(this, filter); updatePowerSave(); @@ -71,9 +79,10 @@ public class BatteryController extends BroadcastReceiver { mChangeCallbacks.remove(cb); } - public void onReceive(Context context, Intent intent) { + public void onReceive(final Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { + if (mTestmode && !intent.getBooleanExtra("testmode", false)) return; mLevel = (int)(100f * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)); @@ -89,6 +98,38 @@ public class BatteryController extends BroadcastReceiver { updatePowerSave(); } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)) { setPowerSave(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false)); + } else if (action.equals(ACTION_LEVEL_TEST)) { + mTestmode = true; + mHandler.post(new Runnable() { + int curLevel = 0; + int incr = 1; + int saveLevel = mLevel; + boolean savePlugged = mPluggedIn; + Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED); + @Override + public void run() { + if (curLevel < 0) { + mTestmode = false; + dummy.putExtra("level", saveLevel); + dummy.putExtra("plugged", savePlugged); + dummy.putExtra("testmode", false); + } else { + dummy.putExtra("level", curLevel); + dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC + : 0); + dummy.putExtra("testmode", true); + } + context.sendBroadcast(dummy); + + if (!mTestmode) return; + + curLevel += incr; + if (curLevel == 100) { + incr *= -1; + } + mHandler.postDelayed(this, 200); + } + }); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java index d907b0072eb1..cec0c0a25b35 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java @@ -18,7 +18,8 @@ package com.android.systemui.statusbar.policy; import android.app.ActivityManager; import android.content.Context; - +import android.os.RemoteException; +import android.view.WindowManagerGlobal; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.settings.CurrentUserTracker; @@ -83,6 +84,20 @@ public final class KeyguardMonitor extends KeyguardUpdateMonitorCallback { return mCanSkipBouncer; } + public void unlock() { + try { + WindowManagerGlobal.getWindowManagerService().dismissKeyguard(); + } catch (RemoteException e) { + } + } + + public void lock() { + try { + WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */); + } catch (RemoteException e) { + } + } + public void notifyKeyguardState(boolean showing, boolean secure) { if (mShowing == showing && mSecure == secure) return; mShowing = showing; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index 0f9dd5cfc70b..e0823b41554d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -182,10 +182,10 @@ public class SecurityControllerImpl implements SecurityController { @Override public void onUserSwitched(int newUserId) { mCurrentUserId = newUserId; - if (mUserManager.getUserInfo(newUserId).isRestricted()) { + final UserInfo newUserInfo = mUserManager.getUserInfo(newUserId); + if (newUserInfo.isRestricted()) { // VPN for a restricted profile is routed through its owner user - // TODO: http://b/22950929 - mVpnUserId = UserHandle.USER_SYSTEM; + mVpnUserId = newUserInfo.restrictedProfileParentId; } else { mVpnUserId = mCurrentUserId; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java index a8d4f131b54e..6931d1ea6a6a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java @@ -71,6 +71,11 @@ public final class UserInfoController { public void addListener(OnUserInfoChangedListener callback) { mCallbacks.add(callback); + callback.onUserInfoChanged(mUserName, mUserDrawable); + } + + public void remListener(OnUserInfoChangedListener callback) { + mCallbacks.remove(callback); } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 81658941b339..e00b8907a01a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -752,9 +752,4 @@ public class UserSwitcherController { } } } - - public static boolean isUserSwitcherAvailable(UserManager um) { - return UserManager.supportsMultipleUsers() && um.isUserSwitcherEnabled(); - } - } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index 2587b9f237c8..bbe5dd90d11f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -171,7 +171,7 @@ public class TvStatusBar extends BaseStatusBar { } @Override - public void onCameraLaunchGestureDetected() { + public void onCameraLaunchGestureDetected(int source) { } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java index 4387b33d0797..04a51f07b1d0 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java @@ -9,8 +9,8 @@ import com.android.systemui.statusbar.phone.QSTileHost; public class QSPagingSwitch extends TunerSwitch { public static final String QS_PAGE_TILES = - "dwifi,dbt,inversion,dnd,cell,airplane,rotation,flashlight,location," - + "hotspot,qwifi,qbt,qrotation,qflashlight,qairplane,cast"; + "dwifi,dbt,dnd,cell,battery,user,rotation,flashlight,location," + + "hotspot,qwifi,qbt,qlock,qflashlight,qairplane,inversion,cast"; public QSPagingSwitch(Context context, AttributeSet attrs) { super(context, attrs); diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java index 772f86643c2b..703ee6610314 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java @@ -206,8 +206,8 @@ public class QsTuner extends Fragment implements Callback { private static class CustomHost extends QSTileHost { public CustomHost(Context context) { - super(context, null, null, null, null, null, null, null, null, null, - null, null, new BlankSecurityController()); + super(context, null, null, null, null, null, null, null, null, null, null, + null, null, new BlankSecurityController(), null); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java index 920f875576a9..9a78b6cbc023 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java @@ -39,7 +39,7 @@ import com.android.systemui.R; import com.android.systemui.qs.QSPanel; import com.android.systemui.tuner.TunerService.Tunable; -import static com.android.systemui.BatteryMeterView.SHOW_PERCENT_SETTING; +import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING; public class TunerFragment extends PreferenceFragment { diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java index 50234b2e1b1b..715593891ccb 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java @@ -33,7 +33,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.ArrayMap; -import com.android.systemui.BatteryMeterView; +import com.android.systemui.BatteryMeterDrawable; import com.android.systemui.DemoMode; import com.android.systemui.R; import com.android.systemui.SystemUI; @@ -135,7 +135,7 @@ public class TunerService extends SystemUI { public void clearAll() { // A couple special cases. Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null); - Settings.System.putString(mContentResolver, BatteryMeterView.SHOW_PERCENT_SETTING, null); + Settings.System.putString(mContentResolver, BatteryMeterDrawable.SHOW_PERCENT_SETTING, null); Intent intent = new Intent(DemoMode.ACTION_DEMO); intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT); mContext.sendBroadcast(intent); diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp index 272733893280..990d7707cdfb 100644 --- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp +++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp @@ -130,7 +130,7 @@ static jstring com_android_pacprocessor_PacNative_makeProxyRequestNativeLocked(J return jret; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "createV8ParserNativeLocked", "()Z", (void*)com_android_pacprocessor_PacNative_createV8ParserNativeLocked}, { "destroyV8ParserNativeLocked", "()Z", diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp index 0419d33c686c..3759c918a519 100644 --- a/rs/jni/android_renderscript_RenderScript.cpp +++ b/rs/jni/android_renderscript_RenderScript.cpp @@ -611,7 +611,7 @@ nScriptIntrinsicBLAS_Double(JNIEnv *_env, jobject _this, jlong con, jlong id, ji in_allocs[2] = (RsAllocation)C; rsScriptForEachMulti((RsContext)con, (RsScript)id, 0, - in_allocs, sizeof(in_allocs), nullptr, + in_allocs, NELEM(in_allocs), nullptr, &call, sizeof(call), nullptr, 0); } @@ -646,7 +646,7 @@ nScriptIntrinsicBLAS_Complex(JNIEnv *_env, jobject _this, jlong con, jlong id, j in_allocs[2] = (RsAllocation)C; rsScriptForEachMulti((RsContext)con, (RsScript)id, 0, - in_allocs, sizeof(in_allocs), nullptr, + in_allocs, NELEM(in_allocs), nullptr, &call, sizeof(call), nullptr, 0); } @@ -681,7 +681,7 @@ nScriptIntrinsicBLAS_Z(JNIEnv *_env, jobject _this, jlong con, jlong id, jint fu in_allocs[2] = (RsAllocation)C; rsScriptForEachMulti((RsContext)con, (RsScript)id, 0, - in_allocs, sizeof(in_allocs), nullptr, + in_allocs, NELEM(in_allocs), nullptr, &call, sizeof(call), nullptr, 0); } @@ -707,7 +707,7 @@ nScriptIntrinsicBLAS_BNNM(JNIEnv *_env, jobject _this, jlong con, jlong id, jint in_allocs[2] = (RsAllocation)C; rsScriptForEachMulti((RsContext)con, (RsScript)id, 0, - in_allocs, sizeof(in_allocs), nullptr, + in_allocs, NELEM(in_allocs), nullptr, &call, sizeof(call), nullptr, 0); } @@ -2494,7 +2494,7 @@ nSystemGetPointerSize(JNIEnv *_env, jobject _this) { static const char *classPathName = "android/renderscript/RenderScript"; -static JNINativeMethod methods[] = { +static const JNINativeMethod methods[] = { {"_nInit", "()V", (void*)_nInit }, {"nDeviceCreate", "()J", (void*)nDeviceCreate }, diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 87a0b808f573..b52687a78298 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -45,28 +45,28 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo /** * Flag for enabling the screen magnification feature. * - * @see #setEnabledFeatures(int) + * @see #setUserAndEnabledFeatures(int, int) */ static final int FLAG_FEATURE_SCREEN_MAGNIFIER = 0x00000001; /** * Flag for enabling the touch exploration feature. * - * @see #setEnabledFeatures(int) + * @see #setUserAndEnabledFeatures(int, int) */ static final int FLAG_FEATURE_TOUCH_EXPLORATION = 0x00000002; /** * Flag for enabling the filtering key events feature. * - * @see #setEnabledFeatures(int) + * @see #setUserAndEnabledFeatures(int, int) */ static final int FLAG_FEATURE_FILTER_KEY_EVENTS = 0x00000004; /** * Flag for enabling "Automatically click on mouse stop" feature. * - * @see #setEnabledFeatures(int) + * @see #setUserAndEnabledFeatures(int, int) */ static final int FLAG_FEATURE_AUTOCLICK = 0x00000008; @@ -97,6 +97,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo private boolean mInstalled; + private int mUserId; + private int mEnabledFeatures; private TouchExplorer mTouchExplorer; @@ -327,13 +329,14 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo /* do nothing */ } - void setEnabledFeatures(int enabledFeatures) { - if (mEnabledFeatures == enabledFeatures) { + void setUserAndEnabledFeatures(int userId, int enabledFeatures) { + if (mEnabledFeatures == enabledFeatures && mUserId == userId) { return; } if (mInstalled) { disableFeatures(); } + mUserId = userId; mEnabledFeatures = enabledFeatures; if (mInstalled) { enableFeatures(); @@ -350,7 +353,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo resetStreamState(); if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) { - mAutoclickController = new AutoclickController(mContext); + mAutoclickController = new AutoclickController(mContext, mUserId); addFirstEventHandler(mAutoclickController); } @@ -360,7 +363,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo } if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) { - mScreenMagnifier = new ScreenMagnifier(mContext, + mScreenMagnifier = new ScreenMagnifier(mContext, mUserId, Display.DEFAULT_DISPLAY, mAms); addFirstEventHandler(mScreenMagnifier); } @@ -386,7 +389,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo mEventHandler = handler; } - void disableFeatures() { + private void disableFeatures() { if (mAutoclickController != null) { mAutoclickController.onDestroy(); mAutoclickController = null; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 91c3d48d1274..749a0807151a 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -967,8 +967,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser( new Intent(AccessibilityService.SERVICE_INTERFACE), - PackageManager.GET_SERVICES - | PackageManager.GET_META_DATA + PackageManager.GET_SERVICES + | PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, mCurrentUserId); @@ -1296,11 +1296,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { inputFilter = mInputFilter; setInputFilter = true; } - mInputFilter.setEnabledFeatures(flags); + mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags); } else { if (mHasInputFilter) { mHasInputFilter = false; - mInputFilter.disableFeatures(); + mInputFilter.setUserAndEnabledFeatures(userState.mUserId, 0); inputFilter = null; setInputFilter = true; } @@ -3217,7 +3217,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: - case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: { + case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: + case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { return AccessibilityWindowInfo.TYPE_SYSTEM; } diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java index 8989625f979a..32833785a186 100644 --- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java +++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java @@ -51,6 +51,8 @@ import android.view.accessibility.AccessibilityEvent; * * It is expected that each instance will receive mouse events from a single mouse device. User of * the class should handle cases where multiple mouse devices are present. + * + * Each instance is associated to a single user (and it does not handle user switch itself). */ public class AutoclickController implements EventStreamTransformation { @@ -60,13 +62,15 @@ public class AutoclickController implements EventStreamTransformation { private EventStreamTransformation mNext; private final Context mContext; + private final int mUserId; // Lazily created on the first mouse motion event. private ClickScheduler mClickScheduler; private ClickDelayObserver mClickDelayObserver; - public AutoclickController(Context context) { + public AutoclickController(Context context, int userId) { mContext = context; + mUserId = userId; } @Override @@ -75,7 +79,7 @@ public class AutoclickController implements EventStreamTransformation { if (mClickScheduler == null) { Handler handler = new Handler(mContext.getMainLooper()); mClickScheduler = new ClickScheduler(handler, DEFAULT_CLICK_DELAY_MS); - mClickDelayObserver = new ClickDelayObserver(handler); + mClickDelayObserver = new ClickDelayObserver(mUserId, handler); mClickDelayObserver.start(mContext.getContentResolver(), mClickScheduler); } @@ -168,9 +172,11 @@ public class AutoclickController implements EventStreamTransformation { private ContentResolver mContentResolver; private ClickScheduler mClickScheduler; + private final int mUserId; - public ClickDelayObserver(Handler handler) { + public ClickDelayObserver(int userId, Handler handler) { super(handler); + mUserId = userId; } /** @@ -199,7 +205,7 @@ public class AutoclickController implements EventStreamTransformation { mContentResolver = contentResolver; mClickScheduler = clickScheduler; mContentResolver.registerContentObserver(mAutoclickDelaySettingUri, false, this, - UserHandle.USER_ALL); + mUserId); // Initialize mClickScheduler's initial delay value. onChange(true, mAutoclickDelaySettingUri); @@ -222,10 +228,9 @@ public class AutoclickController implements EventStreamTransformation { @Override public void onChange(boolean selfChange, Uri uri) { if (mAutoclickDelaySettingUri.equals(uri)) { - // TODO: Plumb current user id down to here and use getIntForUser. - int delay = Settings.Secure.getInt( + int delay = Settings.Secure.getIntForUser( mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY, - DEFAULT_CLICK_DELAY_MS); + DEFAULT_CLICK_DELAY_MS, mUserId); mClickScheduler.updateDelay(delay); } } diff --git a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java index 37276bdb8145..8845bc0246ba 100644 --- a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java +++ b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java @@ -29,7 +29,6 @@ import android.os.AsyncTask; import android.os.Binder; import android.os.Handler; import android.os.Message; -import android.os.SystemClock; import android.provider.Settings; import android.text.TextUtils; import android.util.Property; @@ -137,6 +136,8 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio private final AccessibilityManagerService mAms; + private final int mUserId; + private final int mTapTimeSlop = ViewConfiguration.getJumpTapTimeout(); private final int mMultiTapTimeSlop; private final int mTapDistanceSlop; @@ -188,8 +189,10 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio } }; - public ScreenMagnifier(Context context, int displayId, AccessibilityManagerService service) { + public ScreenMagnifier(Context context, int userId, int displayId, + AccessibilityManagerService service) { mContext = context; + mUserId = userId; mWindowManager = LocalServices.getService(WindowManagerInternal.class); mAms = service; @@ -813,33 +816,12 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio while (mDelayedEventQueue != null) { MotionEventInfo info = mDelayedEventQueue; mDelayedEventQueue = info.mNext; - final long offset = SystemClock.uptimeMillis() - info.mCachedTimeMillis; - MotionEvent event = obtainEventWithOffsetTimeAndDownTime(info.mEvent, offset); - MotionEvent rawEvent = obtainEventWithOffsetTimeAndDownTime(info.mRawEvent, offset); - ScreenMagnifier.this.onMotionEvent(event, rawEvent, info.mPolicyFlags); - event.recycle(); - rawEvent.recycle(); + ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mRawEvent, + info.mPolicyFlags); info.recycle(); } } - private MotionEvent obtainEventWithOffsetTimeAndDownTime(MotionEvent event, long offset) { - final int pointerCount = event.getPointerCount(); - PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount); - PointerProperties[] properties = getTempPointerPropertiesWithMinSize(pointerCount); - for (int i = 0; i < pointerCount; i++) { - event.getPointerCoords(i, coords[i]); - event.getPointerProperties(i, properties[i]); - } - final long downTime = event.getDownTime() + offset; - final long eventTime = event.getEventTime() + offset; - return MotionEvent.obtain(downTime, eventTime, - event.getAction(), pointerCount, properties, coords, - event.getMetaState(), event.getButtonState(), - 1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(), - event.getSource(), event.getFlags()); - } - private void clearDelayedMotionEvents() { while (mDelayedEventQueue != null) { MotionEventInfo info = mDelayedEventQueue; @@ -882,17 +864,17 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { - Settings.Secure.putFloat(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale); + Settings.Secure.putFloatForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale, mUserId); return null; } }.execute(); } private float getPersistedScale() { - return Settings.Secure.getFloat(mContext.getContentResolver(), + return Settings.Secure.getFloatForUser(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, - DEFAULT_MAGNIFICATION_SCALE); + DEFAULT_MAGNIFICATION_SCALE, mUserId); } private static boolean isScreenMagnificationAutoUpdateEnabled(Context context) { @@ -915,7 +897,6 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio public MotionEvent mEvent; public MotionEvent mRawEvent; public int mPolicyFlags; - public long mCachedTimeMillis; public static MotionEventInfo obtain(MotionEvent event, MotionEvent rawEvent, int policyFlags) { @@ -940,7 +921,6 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio mEvent = MotionEvent.obtain(event); mRawEvent = MotionEvent.obtain(rawEvent); mPolicyFlags = policyFlags; - mCachedTimeMillis = SystemClock.uptimeMillis(); } public void recycle() { @@ -964,7 +944,6 @@ public final class ScreenMagnifier implements WindowManagerInternal.Magnificatio mRawEvent.recycle(); mRawEvent = null; mPolicyFlags = 0; - mCachedTimeMillis = 0; } } diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java index 85730cdef082..c3f5c43daeb7 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java @@ -29,6 +29,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.SystemClock; import android.util.Slog; +import android.view.GestureDetector; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; @@ -114,9 +115,6 @@ class TouchExplorer implements EventStreamTransformation { // Timeout within which we try to detect a tap. private final int mTapTimeout; - // Timeout within which we try to detect a double tap. - private final int mDoubleTapTimeout; - // Slop between the down and up tap to be a tap. private final int mTouchSlop; @@ -230,7 +228,6 @@ class TouchExplorer implements EventStreamTransformation { mInjectedPointerTracker = new InjectedPointerTracker(); mTapTimeout = ViewConfiguration.getTapTimeout(); mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout(); - mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout(); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); mHandler = new Handler(context.getMainLooper()); @@ -248,7 +245,7 @@ class TouchExplorer implements EventStreamTransformation { mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed( AccessibilityEvent.TYPE_TOUCH_INTERACTION_END, mDetermineUserIntentTimeout); - mDoubleTapDetector = new DoubleTapDetector(); + mDoubleTapDetector = new DoubleTapDetector(mContext); final float density = context.getResources().getDisplayMetrics().density; mScaledMinPointerDistanceToUseMiddleLocation = (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density); @@ -1109,66 +1106,63 @@ class TouchExplorer implements EventStreamTransformation { } } - private class DoubleTapDetector { - private MotionEvent mDownEvent; - private MotionEvent mFirstTapEvent; + private class DoubleTapDetector extends GestureDetector.SimpleOnGestureListener { + private final GestureDetector mGestureDetector; + private boolean mFirstTapDetected; + private boolean mDoubleTapDetected; + + DoubleTapDetector(Context context) { + mGestureDetector = new GestureDetector(context, this); + mGestureDetector.setOnDoubleTapListener(this); + } public void onMotionEvent(MotionEvent event, int policyFlags) { - final int actionIndex = event.getActionIndex(); - final int action = event.getActionMasked(); - switch (action) { + switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: { - if (mFirstTapEvent != null - && !GestureUtils.isSamePointerContext(mFirstTapEvent, event)) { - clear(); - } - mDownEvent = MotionEvent.obtain(event); - } break; + mDoubleTapDetected = false; + break; + case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: { - if (mDownEvent == null) { - return; - } - if (!GestureUtils.isSamePointerContext(mDownEvent, event)) { - clear(); - return; - } - if (GestureUtils.isTap(mDownEvent, event, mTapTimeout, mTouchSlop, - actionIndex)) { - if (mFirstTapEvent == null || GestureUtils.isTimedOut(mFirstTapEvent, - event, mDoubleTapTimeout)) { - mFirstTapEvent = MotionEvent.obtain(event); - mDownEvent.recycle(); - mDownEvent = null; - return; - } - if (GestureUtils.isMultiTap(mFirstTapEvent, event, mDoubleTapTimeout, - mDoubleTapSlop, actionIndex)) { - onDoubleTap(event, policyFlags); - mFirstTapEvent.recycle(); - mFirstTapEvent = null; - mDownEvent.recycle(); - mDownEvent = null; - return; - } - mFirstTapEvent.recycle(); - mFirstTapEvent = null; - } else { - if (mFirstTapEvent != null) { - mFirstTapEvent.recycle(); - mFirstTapEvent = null; - } - } - mDownEvent.recycle(); - mDownEvent = null; - } break; + maybeFinishDoubleTap(event, policyFlags); + break; } + mGestureDetector.onTouchEvent(event); + } + + @Override + public boolean onDown(MotionEvent event) { + return true; + } + + @Override + public boolean onSingleTapUp(MotionEvent event) { + mFirstTapDetected = true; + return false; } - public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) { + @Override + public boolean onSingleTapConfirmed(MotionEvent event) { + clear(); + return false; + } + + @Override + public boolean onDoubleTap(MotionEvent event) { + // The processing of the double tap is deferred until the finger is + // lifted, so that we can detect a long press on the second tap. + mDoubleTapDetected = true; + return true; + } + + private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) { + if (!mDoubleTapDetected) { + return; + } + + clear(); + // This should never be called when more than two pointers are down. - if (secondTapUp.getPointerCount() > 2) { + if (event.getPointerCount() > 2) { return; } @@ -1184,8 +1178,8 @@ class TouchExplorer implements EventStreamTransformation { mSendTouchInteractionEndDelayed.forceSendAndRemove(); } - final int pointerId = secondTapUp.getPointerId(secondTapUp.getActionIndex()); - final int pointerIndex = secondTapUp.findPointerIndex(pointerId); + final int pointerId = event.getPointerId(event.getActionIndex()); + final int pointerIndex = event.findPointerIndex(pointerId); Point clickLocation = mTempPoint; final int result = computeClickLocation(clickLocation); @@ -1196,34 +1190,28 @@ class TouchExplorer implements EventStreamTransformation { // Do the click. PointerProperties[] properties = new PointerProperties[1]; properties[0] = new PointerProperties(); - secondTapUp.getPointerProperties(pointerIndex, properties[0]); + event.getPointerProperties(pointerIndex, properties[0]); PointerCoords[] coords = new PointerCoords[1]; coords[0] = new PointerCoords(); coords[0].x = clickLocation.x; coords[0].y = clickLocation.y; - MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(), - secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties, - coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0, - secondTapUp.getSource(), secondTapUp.getFlags()); + MotionEvent click_event = MotionEvent.obtain(event.getDownTime(), + event.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties, + coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, + event.getSource(), event.getFlags()); final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS); - sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus); - event.recycle(); + sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus); + click_event.recycle(); + return; } public void clear() { - if (mDownEvent != null) { - mDownEvent.recycle(); - mDownEvent = null; - } - if (mFirstTapEvent != null) { - mFirstTapEvent.recycle(); - mFirstTapEvent = null; - } + mFirstTapDetected = false; + mDoubleTapDetected = false; } public boolean firstTapDetected() { - return mFirstTapEvent != null - && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout; + return mFirstTapDetected; } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6190a5ab357e..a7e6f1187719 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -754,6 +754,8 @@ public class ConnectivityService extends IConnectivityManager.Stub IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTING); intentFilter.addAction(Intent.ACTION_USER_STOPPING); + intentFilter.addAction(Intent.ACTION_USER_ADDED); + intentFilter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiverAsUser( mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); @@ -3525,6 +3527,26 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void onUserAdded(int userId) { + synchronized(mVpns) { + final int vpnsSize = mVpns.size(); + for (int i = 0; i < vpnsSize; i++) { + Vpn vpn = mVpns.valueAt(i); + vpn.onUserAdded(userId); + } + } + } + + private void onUserRemoved(int userId) { + synchronized(mVpns) { + final int vpnsSize = mVpns.size(); + for (int i = 0; i < vpnsSize; i++) { + Vpn vpn = mVpns.valueAt(i); + vpn.onUserRemoved(userId); + } + } + } + private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -3536,6 +3558,10 @@ public class ConnectivityService extends IConnectivityManager.Stub onUserStart(userId); } else if (Intent.ACTION_USER_STOPPING.equals(action)) { onUserStop(userId); + } else if (Intent.ACTION_USER_ADDED.equals(action)) { + onUserAdded(userId); + } else if (Intent.ACTION_USER_REMOVED.equals(action)) { + onUserRemoved(userId); } } }; diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 0c6eb40f5b08..ebcdf7c31901 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -31,6 +31,8 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.database.ContentObserver; import android.hardware.Sensor; import android.hardware.SensorManager; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; import android.hardware.display.DisplayManager; @@ -111,7 +113,7 @@ public class DeviceIdleController extends SystemService private INetworkPolicyManager mNetworkPolicyManager; private DisplayManager mDisplayManager; private SensorManager mSensorManager; - private Sensor mSigMotionSensor; + private Sensor mMotionSensor; private LocationManager mLocationManager; private LocationRequest mLocationRequest; private PendingIntent mSensingAlarmIntent; @@ -123,7 +125,6 @@ public class DeviceIdleController extends SystemService private boolean mForceIdle; private boolean mScreenOn; private boolean mCharging; - private boolean mSigMotionActive; private boolean mSensing; private boolean mNotMoving; private boolean mLocating; @@ -268,13 +269,57 @@ public class DeviceIdleController extends SystemService } }; - private final TriggerEventListener mSigMotionListener = new TriggerEventListener() { - @Override public void onTrigger(TriggerEvent event) { + private final class MotionListener extends TriggerEventListener + implements SensorEventListener { + + boolean active = false; + + @Override + public void onTrigger(TriggerEvent event) { synchronized (DeviceIdleController.this) { - significantMotionLocked(); + active = false; + motionLocked(); + } + } + + @Override + public void onSensorChanged(SensorEvent event) { + synchronized (DeviceIdleController.this) { + mSensorManager.unregisterListener(this, mMotionSensor); + active = false; + motionLocked(); } } - }; + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) {} + + public boolean registerLocked() { + boolean success = false; + if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) { + success = mSensorManager.requestTriggerSensor(mMotionListener, mMotionSensor); + } else { + success = mSensorManager.registerListener( + mMotionListener, mMotionSensor, SensorManager.SENSOR_DELAY_NORMAL); + } + if (success) { + active = true; + } else { + Slog.e(TAG, "Unable to register for " + mMotionSensor); + } + return success; + } + + public void unregisterLocked() { + if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) { + mSensorManager.cancelTriggerSensor(mMotionListener, mMotionSensor); + } else { + mSensorManager.unregisterListener(mMotionListener); + } + active = false; + } + } + private final MotionListener mMotionListener = new MotionListener(); private final LocationListener mGenericLocationListener = new LocationListener() { @Override @@ -349,7 +394,7 @@ public class DeviceIdleController extends SystemService * This is the time, after becoming inactive, at which we start looking at the * motion sensor to determine if the device is being left alone. We don't do this * immediately after going inactive just because we don't want to be continually running - * the significant motion sensor whenever the screen is off. + * the motion sensor whenever the screen is off. * @see Settings.Global#DEVICE_IDLE_CONSTANTS * @see #KEY_INACTIVE_TIMEOUT */ @@ -392,7 +437,7 @@ public class DeviceIdleController extends SystemService /** * This is the time, after the inactive timeout elapses, that we will wait looking - * for significant motion until we truly consider the device to be idle. + * for motion until we truly consider the device to be idle. * @see Settings.Global#DEVICE_IDLE_CONSTANTS * @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT */ @@ -886,18 +931,19 @@ public class DeviceIdleController extends SystemService int sigMotionSensorId = getContext().getResources().getInteger( com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor); if (sigMotionSensorId > 0) { - mSigMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true); + mMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true); } - if (mSigMotionSensor == null && getContext().getResources().getBoolean( + if (mMotionSensor == null && getContext().getResources().getBoolean( com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) { - mSigMotionSensor = mSensorManager.getDefaultSensor( - Sensor.TYPE_WRIST_TILT_GESTURE); + mMotionSensor = mSensorManager.getDefaultSensor( + Sensor.TYPE_WRIST_TILT_GESTURE, true); } - if (mSigMotionSensor == null) { + if (mMotionSensor == null) { // As a last ditch, fall back to SMD. - mSigMotionSensor = mSensorManager.getDefaultSensor( - Sensor.TYPE_SIGNIFICANT_MOTION); + mMotionSensor = mSensorManager.getDefaultSensor( + Sensor.TYPE_SIGNIFICANT_MOTION, true); } + if (getContext().getResources().getBoolean( com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) { mLocationManager = (LocationManager) getContext().getSystemService( @@ -1242,7 +1288,7 @@ public class DeviceIdleController extends SystemService cancelAlarmLocked(); cancelSensingAlarmLocked(); cancelLocatingLocked(); - stopMonitoringSignificantMotion(); + stopMonitoringMotionLocked(); mAnyMotionDetector.stop(); } @@ -1271,8 +1317,8 @@ public class DeviceIdleController extends SystemService switch (mState) { case STATE_INACTIVE: // We have now been inactive long enough, it is time to start looking - // for significant motion and sleep some more while doing so. - startMonitoringSignificantMotion(); + // for motion and sleep some more while doing so. + startMonitoringMotionLocked(); scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false); // Reset the upcoming idle delays. mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT; @@ -1353,17 +1399,16 @@ public class DeviceIdleController extends SystemService } } - void significantMotionLocked() { - if (DEBUG) Slog.d(TAG, "significantMotionLocked()"); - // When the sensor goes off, its trigger is automatically removed. - mSigMotionActive = false; + void motionLocked() { + if (DEBUG) Slog.d(TAG, "motionLocked()"); + // The motion sensor will have been disabled at this point handleMotionDetectedLocked(mConstants.MOTION_INACTIVE_TIMEOUT, "motion"); } void handleMotionDetectedLocked(long timeout, String type) { // The device is not yet active, so we want to go back to the pending idle - // state to wait again for no motion. Note that we only monitor for significant - // motion after moving out of the inactive state, so no need to worry about that. + // state to wait again for no motion. Note that we only monitor for motion + // after moving out of the inactive state, so no need to worry about that. if (mState != STATE_ACTIVE) { scheduleReportActiveLocked(type, Process.myUid()); mState = STATE_ACTIVE; @@ -1405,19 +1450,17 @@ public class DeviceIdleController extends SystemService } } - void startMonitoringSignificantMotion() { - if (DEBUG) Slog.d(TAG, "startMonitoringSignificantMotion()"); - if (mSigMotionSensor != null && !mSigMotionActive) { - mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor); - mSigMotionActive = true; + void startMonitoringMotionLocked() { + if (DEBUG) Slog.d(TAG, "startMonitoringMotionLocked()"); + if (mMotionSensor != null && !mMotionListener.active) { + mMotionListener.registerLocked(); } } - void stopMonitoringSignificantMotion() { - if (DEBUG) Slog.d(TAG, "stopMonitoringSignificantMotion()"); - if (mSigMotionActive) { - mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor); - mSigMotionActive = false; + void stopMonitoringMotionLocked() { + if (DEBUG) Slog.d(TAG, "stopMonitoringMotionLocked()"); + if (mMotionSensor != null && mMotionListener.active) { + mMotionListener.unregisterLocked(); } } @@ -1446,7 +1489,7 @@ public class DeviceIdleController extends SystemService void scheduleAlarmLocked(long delay, boolean idleUntil) { if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")"); - if (mSigMotionSensor == null) { + if (mMotionSensor == null) { // If there is no motion sensor on this device, then we won't schedule // alarms, because we can't determine if the device is not moving. This effectively // turns off normal execution of device idling, although it is still possible to @@ -1929,11 +1972,11 @@ public class DeviceIdleController extends SystemService pw.print(" mEnabled="); pw.println(mEnabled); pw.print(" mForceIdle="); pw.println(mForceIdle); - pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor); + pw.print(" mMotionSensor="); pw.println(mMotionSensor); pw.print(" mCurDisplay="); pw.println(mCurDisplay); pw.print(" mScreenOn="); pw.println(mScreenOn); pw.print(" mCharging="); pw.println(mCharging); - pw.print(" mSigMotionActive="); pw.println(mSigMotionActive); + pw.print(" mMotionActive="); pw.println(mMotionListener.active); pw.print(" mSensing="); pw.print(mSensing); pw.print(" mNotMoving="); pw.println(mNotMoving); pw.print(" mLocating="); pw.print(mLocating); pw.print(" mHasGps="); diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java index 7c85001c9175..f2459852d706 100644 --- a/services/core/java/com/android/server/GestureLauncherService.java +++ b/services/core/java/com/android/server/GestureLauncherService.java @@ -17,6 +17,7 @@ package com.android.server; import android.app.ActivityManager; +import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -263,7 +264,8 @@ public class GestureLauncherService extends SystemService { } if (launched) { Slog.i(TAG, "Power button double tap gesture detected, launching camera."); - launched = handleCameraLaunchGesture(false /* useWakelock */); + launched = handleCameraLaunchGesture(false /* useWakelock */, + StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP); if (launched) { MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) doubleTapInterval); @@ -276,7 +278,7 @@ public class GestureLauncherService extends SystemService { /** * @return true if camera was launched, false otherwise. */ - private boolean handleCameraLaunchGesture(boolean useWakelock) { + private boolean handleCameraLaunchGesture(boolean useWakelock, int source) { boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 0) != 0; if (!userSetupComplete) { @@ -295,7 +297,7 @@ public class GestureLauncherService extends SystemService { } StatusBarManagerInternal service = LocalServices.getService( StatusBarManagerInternal.class); - service.onCameraLaunchGestureDetected(); + service.onCameraLaunchGestureDetected(source); return true; } @@ -334,7 +336,8 @@ public class GestureLauncherService extends SystemService { Slog.d(TAG, String.format("Received a camera launch event: " + "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2])); } - if (handleCameraLaunchGesture(true /* useWakelock */)) { + if (handleCameraLaunchGesture(true /* useWakelock */, + StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) { MetricsLogger.action(mContext, MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE); trackCameraLaunchEvent(event); } diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 885c765f3f4b..087ddd6fd882 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -211,8 +211,8 @@ public class LocationManagerService extends ILocationManager.Stub { new ArrayList<LocationProviderProxy>(); // current active user on the device - other users are denied location data - private int mCurrentUserId = UserHandle.USER_OWNER; - private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER }; + private int mCurrentUserId = UserHandle.USER_SYSTEM; + private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM }; public LocationManagerService(Context context) { super(); @@ -1832,7 +1832,8 @@ public class LocationManagerService extends ILocationManager.Stub { // geo-fence manager uses the public location API, need to clear identity int uid = Binder.getCallingUid(); - if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) { + // TODO: http://b/23822629 + if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) { // temporary measure until geofences work for secondary users Log.w(TAG, "proximity alerts are currently available only to the primary user"); return; diff --git a/services/core/java/com/android/server/ThermalObserver.java b/services/core/java/com/android/server/ThermalObserver.java new file mode 100644 index 000000000000..aee28fb6b295 --- /dev/null +++ b/services/core/java/com/android/server/ThermalObserver.java @@ -0,0 +1,146 @@ +/* + * 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.Intent; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Handler; +import android.os.Message; +import android.os.PowerManager; +import android.os.UEventObserver; +import android.os.UserHandle; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * ThermalObserver for monitoring temperature changes. + */ +public class ThermalObserver extends SystemService { + private static final String TAG = "ThermalObserver"; + + private static final String CALLSTATE_UEVENT_MATCH = + "DEVPATH=/devices/virtual/switch/thermalstate"; + + private static final int MSG_THERMAL_STATE_CHANGED = 0; + + private static final int SWITCH_STATE_NORMAL = 0; + private static final int SWITCH_STATE_WARNING = 1; + private static final int SWITCH_STATE_EXCEEDED = 2; + + private final PowerManager mPowerManager; + private final PowerManager.WakeLock mWakeLock; + + private final Object mLock = new Object(); + private Integer mLastState; + + private final UEventObserver mThermalWarningObserver = new UEventObserver() { + @Override + public void onUEvent(UEventObserver.UEvent event) { + updateLocked(Integer.parseInt(event.get("SWITCH_STATE"))); + } + }; + + private final Handler mHandler = new Handler(true /*async*/) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_THERMAL_STATE_CHANGED: + handleThermalStateChange(msg.arg1); + mWakeLock.release(); + break; + } + } + }; + + public ThermalObserver(Context context) { + super(context); + mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + + mThermalWarningObserver.startObserving(CALLSTATE_UEVENT_MATCH); + } + + private void updateLocked(int state) { + Message message = new Message(); + message.what = MSG_THERMAL_STATE_CHANGED; + message.arg1 = state; + + mWakeLock.acquire(); + mHandler.sendMessage(message); + } + + private void handleThermalStateChange(int state) { + synchronized (mLock) { + mLastState = state; + Intent intent = new Intent(Intent.ACTION_THERMAL_EVENT); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + + final int thermalState; + + switch (state) { + case SWITCH_STATE_WARNING: + thermalState = Intent.EXTRA_THERMAL_STATE_WARNING; + break; + case SWITCH_STATE_EXCEEDED: + thermalState = Intent.EXTRA_THERMAL_STATE_EXCEEDED; + break; + case SWITCH_STATE_NORMAL: + default: + thermalState = Intent.EXTRA_THERMAL_STATE_NORMAL; + break; + } + + intent.putExtra(Intent.EXTRA_THERMAL_STATE, thermalState); + + getContext().sendBroadcastAsUser(intent, UserHandle.ALL); + } + } + + @Override + public void onStart() { + publishBinderService(TAG, new BinderService()); + } + + private final class BinderService extends Binder { + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump thermal observer service from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + if (args == null || args.length == 0 || "-a".equals(args[0])) { + pw.println("Current Thermal Observer Service state:"); + pw.println(" last state change: " + + (mLastState != null ? mLastState : "none")); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } +} diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index dbf128840c59..6b346123e94a 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -29,6 +29,7 @@ import android.accounts.IAccountAuthenticator; import android.accounts.IAccountAuthenticatorResponse; import android.accounts.IAccountManager; import android.accounts.IAccountManagerResponse; +import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.AppGlobals; @@ -2526,6 +2527,7 @@ public class AccountManagerService * Returns the accounts visible to the client within the context of a specific user * @hide */ + @NonNull public Account[] getAccounts(int userId, String opPackageName) { int callingUid = Binder.getCallingUid(); List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId, @@ -2551,6 +2553,7 @@ public class AccountManagerService * * @hide */ + @NonNull public AccountAndUser[] getRunningAccounts() { final int[] runningUserIds; try { @@ -2563,6 +2566,7 @@ public class AccountManagerService } /** {@hide} */ + @NonNull public AccountAndUser[] getAllAccounts() { final List<UserInfo> users = getUserManager().getUsers(); final int[] userIds = new int[users.size()]; @@ -2572,6 +2576,7 @@ public class AccountManagerService return getAccounts(userIds); } + @NonNull private AccountAndUser[] getAccounts(int[] userIds) { final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList(); for (int userId : userIds) { @@ -2591,10 +2596,12 @@ public class AccountManagerService } @Override + @NonNull public Account[] getAccountsAsUser(String type, int userId, String opPackageName) { return getAccountsAsUser(type, userId, null, -1, opPackageName); } + @NonNull private Account[] getAccountsAsUser( String type, int userId, @@ -2649,6 +2656,7 @@ public class AccountManagerService } } + @NonNull private Account[] getAccountsInternal( UserAccounts userAccounts, int callingUid, @@ -2672,7 +2680,15 @@ public class AccountManagerService } @Override - public boolean addSharedAccountAsUser(Account account, int userId) { + public void addSharedAccountsFromParentUser(int parentUserId, int userId) { + checkManageUsersPermission("addSharedAccountsFromParentUser"); + Account[] accounts = getAccountsAsUser(null, parentUserId, mContext.getOpPackageName()); + for (Account account : accounts) { + addSharedAccountAsUser(account, userId); + } + } + + private boolean addSharedAccountAsUser(Account account, int userId) { userId = handleIncomingUser(userId); UserAccounts accounts = getUserAccounts(userId); SQLiteDatabase db = accounts.openHelper.getWritableDatabase(); @@ -2764,11 +2780,13 @@ public class AccountManagerService } @Override + @NonNull public Account[] getAccounts(String type, String opPackageName) { return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName); } @Override + @NonNull public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) { int callingUid = Binder.getCallingUid(); if (!UserHandle.isSameApp(callingUid, Process.myUid())) { @@ -2780,6 +2798,7 @@ public class AccountManagerService } @Override + @NonNull public Account[] getAccountsByTypeForPackage(String type, String packageName, String opPackageName) { int packageUid = -1; @@ -3844,6 +3863,14 @@ public class AccountManagerService return false; } + private static void checkManageUsersPermission(String message) { + if (ActivityManager.checkComponentPermission( + android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need MANAGE_USERS permission to: " + message); + } + } + private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType, int callerUid) { if (callerUid == Process.SYSTEM_UID) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f5df9c3482fb..bd10c63edbda 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -994,6 +994,8 @@ public final class ActivityManagerService extends ActivityManagerNative */ int mConfigurationSeq = 0; + boolean mSuppressResizeConfigChanges = false; + /** * Hardware-reported OpenGLES version. */ @@ -2021,7 +2023,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent, PendingIntent.FLAG_CANCEL_CURRENT, null, new UserHandle(userId))) .setDeleteIntent(PendingIntent.getBroadcastAsUser(mContext, 0, - deleteIntent, 0, UserHandle.OWNER)) + deleteIntent, 0, UserHandle.SYSTEM)) .build(); try { @@ -2379,8 +2381,8 @@ public final class ActivityManagerService extends ActivityManagerNative mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml")); // User 0 is the first and only user that runs at boot. - mStartedUsers.put(UserHandle.USER_OWNER, new UserState(UserHandle.OWNER, true)); - mUserLru.add(UserHandle.USER_OWNER); + mStartedUsers.put(UserHandle.USER_SYSTEM, new UserState(UserHandle.SYSTEM, true)); + mUserLru.add(UserHandle.USER_SYSTEM); updateStartedUserArrayLocked(); GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", @@ -5647,7 +5649,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { // Entire package setting changed enabled = pm.getApplicationEnabledSetting(packageName, - (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER); + (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_SYSTEM); } catch (Exception e) { // No such package/component; probably racing with uninstall. In any // event it means we have nothing further to do here. @@ -5665,7 +5667,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { enabled = pm.getComponentEnabledSetting( new ComponentName(packageName, changedClass), - (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER); + (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_SYSTEM); } catch (Exception e) { // As above, probably racing with uninstall. return; @@ -9392,7 +9394,7 @@ public final class ActivityManagerService extends ActivityManagerNative (ProviderInfo)providers.get(i); boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags); - if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_OWNER) { + if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) { // This is a singleton provider, but a user besides the // default user is asking to initialize a process it runs // in... well, no, it doesn't actually run in this process, @@ -9614,7 +9616,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, + private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) { ContentProviderRecord cpr; ContentProviderConnection conn = null; @@ -9642,14 +9644,14 @@ public final class ActivityManagerService extends ActivityManagerNative cpr = mProviderMap.getProviderByName(name, userId); // If that didn't work, check if it exists for user 0 and then // verify that it's a singleton provider before using it. - if (cpr == null && userId != UserHandle.USER_OWNER) { - cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER); + if (cpr == null && userId != UserHandle.USER_SYSTEM) { + cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM); if (cpr != null) { cpi = cpr.info; if (isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) { - userId = UserHandle.USER_OWNER; + userId = UserHandle.USER_SYSTEM; checkCrossUser = false; } else { cpr = null; @@ -9742,7 +9744,6 @@ public final class ActivityManagerService extends ActivityManagerNative Binder.restoreCallingIdentity(origId); } - boolean singleton; if (!providerRunning) { try { checkTime(startTime, "getContentProviderImpl: before resolveContentProvider"); @@ -9759,11 +9760,11 @@ public final class ActivityManagerService extends ActivityManagerNative // (it's a call within the same user || the provider is a // privileged app) // Then allow connecting to the singleton provider - singleton = isSingleton(cpi.processName, cpi.applicationInfo, + boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags) && isValidSingletonCall(r.uid, cpi.applicationInfo.uid); if (singleton) { - userId = UserHandle.USER_OWNER; + userId = UserHandle.USER_SYSTEM; } cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId); checkTime(startTime, "getContentProviderImpl: got app info for user"); @@ -10366,7 +10367,7 @@ public final class ActivityManagerService extends ActivityManagerNative } final ProcessRecord r = new ProcessRecord(stats, info, proc, uid); if (!mBooted && !mBooting - && userId == UserHandle.USER_OWNER + && userId == UserHandle.USER_SYSTEM && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) { r.persistent = true; } @@ -11823,12 +11824,12 @@ public final class ActivityManagerService extends ActivityManagerNative } private boolean deliverPreBootCompleted(final Runnable onFinishCallback, - ArrayList<ComponentName> doneReceivers, int userId) { + ArrayList<ComponentName> doneReceivers) { Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); List<ResolveInfo> ris = null; try { ris = AppGlobals.getPackageManager().queryIntentReceivers( - intent, null, 0, userId); + intent, null, 0, UserHandle.USER_SYSTEM); } catch (RemoteException e) { } if (ris == null) { @@ -11842,22 +11843,18 @@ public final class ActivityManagerService extends ActivityManagerNative } intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE); - // For User 0, load the version number. When delivering to a new user, deliver - // to all receivers. - if (userId == UserHandle.USER_OWNER) { - ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers(); - for (int i=0; i<ris.size(); i++) { - ActivityInfo ai = ris.get(i).activityInfo; - ComponentName comp = new ComponentName(ai.packageName, ai.name); - if (lastDoneReceivers.contains(comp)) { - // We already did the pre boot receiver for this app with the current - // platform version, so don't do it again... - ris.remove(i); - i--; - // ...however, do keep it as one that has been done, so we don't - // forget about it when rewriting the file of last done receivers. - doneReceivers.add(comp); - } + ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers(); + for (int i=0; i<ris.size(); i++) { + ActivityInfo ai = ris.get(i).activityInfo; + ComponentName comp = new ComponentName(ai.packageName, ai.name); + if (lastDoneReceivers.contains(comp)) { + // We already did the pre boot receiver for this app with the current + // platform version, so don't do it again... + ris.remove(i); + i--; + // ...however, do keep it as one that has been done, so we don't + // forget about it when rewriting the file of last done receivers. + doneReceivers.add(comp); } } @@ -11865,9 +11862,8 @@ public final class ActivityManagerService extends ActivityManagerNative return false; } - // If primary user, send broadcast to all available users, else just to userId - final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked() - : new int[] { userId }; + // TODO: can we still do this with per user encryption? + final int[] users = getUsersLocked(); if (users.length <= 0) { return false; } @@ -11918,7 +11914,7 @@ public final class ActivityManagerService extends ActivityManagerNative writeLastDonePreBootReceivers(doneReceivers); systemReady(goingCallback); } - }, doneReceivers, UserHandle.USER_OWNER); + }, doneReceivers); if (mWaitingUpdate) { return; @@ -17521,6 +17517,15 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override + public void suppressResizeConfigChanges(boolean suppress) throws RemoteException { + enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, + "suppressResizeConfigChanges()"); + synchronized (this) { + mSuppressResizeConfigChanges = suppress; + } + } + + @Override public void updatePersistentConfiguration(Configuration values) { enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, "updateConfiguration()"); @@ -20172,7 +20177,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) { - if (userId != UserHandle.USER_OWNER) { + if (userId != UserHandle.USER_SYSTEM) { Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); broadcastIntentLocked(null, null, intent, null, @@ -20410,7 +20415,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i = 0; i < num; i++) { Integer oldUserId = mUserLru.get(i); UserState oldUss = mStartedUsers.get(oldUserId); - if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId + if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId || oldUss.mState == UserState.STATE_STOPPING || oldUss.mState == UserState.STATE_SHUTDOWN) { continue; @@ -20495,8 +20500,12 @@ public final class ActivityManagerService extends ActivityManagerNative i++; continue; } - if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) { - // Owner and current can't be stopped, but count as running. + if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) { + // Owner/System user and current user can't be stopped. We count it as running + // when it is not a pure system user. + if (UserInfo.isSystemOnly(oldUserId)) { + num--; + } i++; continue; } @@ -20519,8 +20528,8 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, msg); throw new SecurityException(msg); } - if (userId < 0 || userId == UserHandle.USER_OWNER) { - throw new IllegalArgumentException("Can't stop primary user " + userId); + if (userId < 0 || userId == UserHandle.USER_SYSTEM) { + throw new IllegalArgumentException("Can't stop system user " + userId); } enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId); synchronized (this) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index cf4a25e6dae3..a796ea7d4ab5 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -529,21 +529,15 @@ final class ActivityStack { * */ void moveToFront(String reason, TaskRecord task) { if (isAttached()) { - final boolean homeStack = isHomeStack() - || (mActivityContainer.mParentActivity != null - && mActivityContainer.mParentActivity.isHomeActivity()); - ActivityStack lastFocusStack = null; - if (!homeStack) { - // Need to move this stack to the front before calling - // {@link ActivityStackSupervisor#moveHomeStack} below. - lastFocusStack = mStacks.get(mStacks.size() - 1); - mStacks.remove(this); - mStacks.add(this); - } - // TODO(multi-display): Focus stack currently adjusted in call to move home stack. - // Needs to also work if focus is moving to the non-home display. + final ActivityStack lastFocusStack = mStacks.get(mStacks.size() - 1); + // Need to move this stack to the front before calling + // {@link ActivityStackSupervisor#setFocusStack} below. + mStacks.remove(this); + mStacks.add(this); + + // TODO(multi-display): Needs to also work if focus is moving to the non-home display. if (isOnHomeDisplay()) { - mStackSupervisor.moveHomeStack(homeStack, reason, lastFocusStack); + mStackSupervisor.setFocusStack(reason, lastFocusStack); } if (task != null) { insertTaskAtTop(task, null); @@ -1336,17 +1330,28 @@ final class ActivityStack { return topHomeActivity == null || !topHomeActivity.isHomeActivity(); } - if (focusedStackId == DOCKED_STACK_ID - && stackIndex == (mStacks.indexOf(focusedStack) - 1)) { + final int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1; + if (focusedStackId == DOCKED_STACK_ID && stackIndex == belowFocusedIndex) { // Stacks directly behind the docked stack are always visible. return true; } - if (mStackId == HOME_STACK_ID && focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID) { - // Home stack is always visible behind the fullscreen stack with a translucent activity. - // This is done so that the home stack can act as a background to the translucent - // activity. - return hasTranslucentActivity(focusedStack); + if (focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID + && hasTranslucentActivity(focusedStack)) { + // Stacks behind the fullscreen stack with a translucent activity are always + // visible so they can act as a backdrop to the translucent activity. + // For example, dialog activities + if (stackIndex == belowFocusedIndex) { + return true; + } + if (belowFocusedIndex >= 0) { + final ActivityStack stack = mStacks.get(belowFocusedIndex); + if (stack.mStackId == DOCKED_STACK_ID && stackIndex == (belowFocusedIndex - 1)) { + // The stack behind the docked stack is also visible so we can have a complete + // backdrop to the translucent activity when the docked stack is up. + return true; + } + } } if (mStackId >= FIRST_STATIC_STACK_ID && mStackId <= LAST_STATIC_STACK_ID) { @@ -1952,7 +1957,6 @@ final class ActivityStack { ? AppTransition.TRANSIT_ACTIVITY_CLOSE : AppTransition.TRANSIT_TASK_CLOSE, false); } - mWindowManager.setAppWillBeHidden(prev.appToken); mWindowManager.setAppVisibility(prev.appToken, false); } else { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, @@ -1968,10 +1972,6 @@ final class ActivityStack { : AppTransition.TRANSIT_TASK_OPEN, false); } } - if (false) { - mWindowManager.setAppWillBeHidden(prev.appToken); - mWindowManager.setAppVisibility(prev.appToken, false); - } } else { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous"); if (mNoAnimActivities.contains(next)) { @@ -4176,8 +4176,12 @@ final class ActivityStack { | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) == 0; } - private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume, - boolean preserveWindow) { + private void relaunchActivityLocked( + ActivityRecord r, int changes, boolean andResume, boolean preserveWindow) { + if (mService.mSuppressResizeConfigChanges && preserveWindow) { + return; + } + List<ResultInfo> results = null; List<ReferrerIntent> newIntents = null; if (andResume) { @@ -4217,8 +4221,6 @@ final class ActivityStack { mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); r.state = ActivityState.PAUSED; } - - return true; } boolean willActivityBeVisibleLocked(IBinder token) { @@ -4543,18 +4545,17 @@ final class ActivityStack { if (mTaskHistory.isEmpty()) { if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this); - final boolean notHomeStack = !isHomeStack(); if (isOnHomeDisplay()) { String myReason = reason + " leftTaskHistoryEmpty"; if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) { - mStackSupervisor.moveHomeStack(notHomeStack, myReason); + mStackSupervisor.moveHomeStackToFront(myReason); } } if (mStacks != null) { mStacks.remove(this); mStacks.add(0, this); } - if (notHomeStack) { + if (!isHomeStack()) { mActivityContainer.onTaskListEmptyLocked(); } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 8c856a82a1c3..6b5f2056ec82 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -24,6 +24,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG; import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; @@ -87,6 +88,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.Trace; import android.os.TransactionTooLargeException; import android.os.UserHandle; import android.os.WorkSource; @@ -468,35 +470,22 @@ public final class ActivityStackSupervisor implements DisplayListener { return stack == mFocusedStack; } - void moveHomeStack(boolean toFront, String reason) { - moveHomeStack(toFront, reason, null); - } - - void moveHomeStack(boolean toFront, String reason, ActivityStack lastFocusedStack) { + void setFocusStack(String reason, ActivityStack lastFocusedStack) { ArrayList<ActivityStack> stacks = mHomeStack.mStacks; final int topNdx = stacks.size() - 1; if (topNdx <= 0) { return; } - // 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_STACK, "moveHomeTask: topStack old=" - + ((lastFocusedStack != null) ? lastFocusedStack : stacks.get(topNdx)) - + " new=" + mFocusedStack); - stacks.remove(mHomeStack); - stacks.add(toFront ? topNdx : 0, mHomeStack); - } - + final ActivityStack topStack = stacks.get(topNdx); + mFocusedStack = topStack; if (lastFocusedStack != null) { mLastFocusedStack = lastFocusedStack; } - mFocusedStack = stacks.get(topNdx); - EventLog.writeEvent(EventLogTags.AM_HOME_STACK_MOVED, - mCurrentUser, toFront ? 1 : 0, stacks.get(topNdx).getStackId(), - mFocusedStack == null ? -1 : mFocusedStack.getStackId(), reason); + EventLogTags.writeAmFocusedStack( + mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(), + mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason); if (mService.mBooting || !mService.mBooted) { final ActivityRecord r = topRunningActivityLocked(); @@ -506,6 +495,10 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + void moveHomeStackToFront(String reason) { + mHomeStack.moveToFront(reason); + } + /** Returns true if the focus activity was adjusted to the home stack top activity. */ boolean moveHomeStackTaskToTop(int homeStackTaskType, String reason) { if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) { @@ -1357,8 +1350,7 @@ public final class ActivityStackSupervisor implements DisplayListener { r.launchFailed = false; if (stack.updateLRUListLocked(r)) { - Slog.w(TAG, "Activity " + r - + " being launched, but already in LRU list"); + Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list"); } if (andResume) { @@ -1807,8 +1799,11 @@ public final class ActivityStackSupervisor implements DisplayListener { return container.mStack; } - if (mFocusedStack != mHomeStack && (!newTask || - mFocusedStack.mActivityContainer.isEligibleForNewTasks())) { + // The fullscreen stack is the only stack that can contain any task regardless of if + // the task is resizeable or not. So, we let the task go in the fullscreen task if it + // is the focus stack. + if (mFocusedStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID + && (!newTask || mFocusedStack.mActivityContainer.isEligibleForNewTasks())) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: Have a focused stack=" + mFocusedStack); return mFocusedStack; @@ -1827,7 +1822,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } // If there is no suitable dynamic stack then we figure out which static stack to use. - int stackId = task != null ? task.getLaunchStackId() : + final int stackId = task != null ? task.getLaunchStackId() : bounds != null ? FREEFORM_WORKSPACE_STACK_ID : FULLSCREEN_WORKSPACE_STACK_ID; stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP); @@ -2974,6 +2969,8 @@ public final class ActivityStackSupervisor implements DisplayListener { return; } + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId); + ActivityRecord r = stack.topRunningActivityLocked(null); mTmpBounds.clear(); @@ -3057,6 +3054,8 @@ public final class ActivityStackSupervisor implements DisplayListener { resumeTopActivitiesLocked(stack, null, null); } } + + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode) { @@ -3085,6 +3084,8 @@ public final class ActivityStackSupervisor implements DisplayListener { return; } + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId); + // The stack of a task is determined by its size (fullscreen vs non-fullscreen). // Place the task in the right stack if it isn't there already based on the requested // bounds. @@ -3109,27 +3110,20 @@ public final class ActivityStackSupervisor implements DisplayListener { ActivityRecord r = task.topRunningActivityLocked(null); if (r != null) { final ActivityStack stack = task.stack; - final boolean resizedByUser = resizeMode == RESIZE_MODE_USER; - final boolean preserveWindow = resizedByUser && !changedStacks; + final boolean preserveWindow = !changedStacks && + (resizeMode == RESIZE_MODE_USER + || resizeMode == RESIZE_MODE_SYSTEM_SCREEN_ROTATION); kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow); // All other activities must be made visible with their correct configuration. ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS); if (!kept) { resumeTopActivitiesLocked(stack, null, null); - if (changedStacks && stackId == FULLSCREEN_WORKSPACE_STACK_ID) { - // We are about to relaunch the activity because its configuration changed - // due to being maximized, i.e. size change. The activity will first - // remove the old window and then add a new one. This call will tell window - // manager about this, so it can preserve the old window until the new - // one is drawn. This prevents having a gap between the removal and - // addition, in which no window is visible. We also want the entrace of the - // new window to be properly animated. - mWindowManager.setReplacingWindow(r.appToken, true /* animate */); - } } } } mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced); + + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) { @@ -3216,7 +3210,13 @@ public final class ActivityStackSupervisor implements DisplayListener { final boolean wasFocused = isFrontStack(task.stack) && (topRunningActivityLocked() == r); final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r); + final boolean resizeable = task.mResizeable; + // Temporarily disable resizeablility of task we are moving. We don't want it to be resized + // if a docked stack is created below which will lead to the stack we are moving from and + // its resizeable tasks being resized. + task.mResizeable = false; final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop); + task.mResizeable = resizeable; mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop); if (task.stack != null) { task.stack.removeTask(task, reason, MOVING); @@ -3246,6 +3246,16 @@ public final class ActivityStackSupervisor implements DisplayListener { return; } final String reason = "moveTaskToStack"; + if (stackId == DOCKED_STACK_ID || stackId == FULLSCREEN_WORKSPACE_STACK_ID) { + // We are about to relaunch the activity because its configuration changed due to + // being maximized, i.e. size change. The activity will first remove the old window + // and then add a new one. This call will tell window manager about this, so it can + // preserve the old window until the new one is drawn. This prevents having a gap + // between the removal and addition, in which no window is visible. We also want the + // entrace of the new window to be properly animated. + ActivityRecord r = task.getTopActivity(); + mWindowManager.setReplacingWindow(r.appToken, true /* animate */); + } final ActivityStack stack = moveTaskToStackUncheckedLocked(task, stackId, toTop, forceFocus, reason); @@ -3657,11 +3667,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } final boolean homeInFront = stack.isHomeStack(); if (stack.isOnHomeDisplay()) { - moveHomeStack(homeInFront, "switchUserOnHomeDisplay"); - TaskRecord task = stack.topTask(); - if (task != null) { - mWindowManager.moveTaskToTop(task.taskId); - } + stack.moveToFront("switchUserOnHomeDisplay"); } else { // Stack was moved to another display while user was swapped out. resumeHomeStackTask(HOME_ACTIVITY_TYPE, null, "switchUserOnOtherDisplay"); @@ -4621,16 +4627,6 @@ public final class ActivityStackSupervisor implements DisplayListener { return mActivityDisplay != null; } - void getBounds(Point outBounds) { - synchronized (mService) { - if (mActivityDisplay != null) { - mActivityDisplay.getBounds(outBounds); - } else { - outBounds.set(0, 0); - } - } - } - // TODO: Make sure every change to ActivityRecord.visible results in a call to this. void setVisible(boolean visible) { if (mVisible != visible) { @@ -4802,12 +4798,6 @@ public final class ActivityStackSupervisor implements DisplayListener { mStacks.remove(stack); } - void getBounds(Point bounds) { - mDisplay.getDisplayInfo(mDisplayInfo); - bounds.x = mDisplayInfo.appWidth; - bounds.y = mDisplayInfo.appHeight; - } - void setVisibleBehindActivity(ActivityRecord r) { mVisibleBehindActivity = r; } diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index 9a645dfc6985..78b5f3333b2c 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -93,8 +93,8 @@ option java_package com.android.server.am # Activity focused 30043 am_focused_activity (User|1|5),(Component Name|3) -# Home Stack brought to front or rear -30044 am_home_stack_moved (User|1|5),(To Front|1|5),(Top Stack Id|1|5),(Focused Stack Id|1|5),(Reason|3) +# Stack focus +30044 am_focused_stack (User|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3) # Running pre boot receiver 30045 am_pre_boot (User|1|5),(Package|3) diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 43f5baab793f..7e14b2b78f0f 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -1193,7 +1193,7 @@ final class TaskRecord { mOverrideConfig = Configuration.EMPTY; } else { mBounds = new Rect(bounds); - if (stack.mStackId != DOCKED_STACK_ID) { + if (stack == null || stack.mStackId != DOCKED_STACK_ID) { mLastNonFullscreenBounds = mBounds; } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 99ca050c9ae7..e49a7e49822c 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2524,11 +2524,14 @@ public class AudioService extends IAudioService.Stub { } /** @see AudioManager#setBluetoothScoOn(boolean) */ - public void setBluetoothScoOn(boolean on){ + public void setBluetoothScoOn(boolean on) { if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { return; } + setBluetoothScoOnInt(on); + } + public void setBluetoothScoOnInt(boolean on) { if (on) { mForcedUseForComm = AudioSystem.FORCE_BT_SCO; } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { @@ -2889,6 +2892,8 @@ public class AudioService extends IAudioService.Stub { mScoAudioState = SCO_STATE_INACTIVE; broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); } + AudioSystem.setParameters("A2dpSuspended=false"); + setBluetoothScoOnInt(false); } private void broadcastScoConnectionState(int state) { diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 3df3cd0b587b..2bea278aad1a 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -20,9 +20,6 @@ import static android.Manifest.permission.BIND_VPN_SERVICE; import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNREACHABLE; -import static android.os.UserHandle.PER_USER_RANGE; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; import android.Manifest; import android.app.AppGlobals; @@ -34,13 +31,11 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.net.ConnectivityManager; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.IpPrefix; import android.net.LinkAddress; @@ -126,7 +121,6 @@ public class Vpn { /* list of users using this VPN. */ @GuardedBy("this") private List<UidRange> mVpnUsers = null; - private BroadcastReceiver mUserIntentReceiver = null; // Handle of user initiating VPN. private final int mUserHandle; @@ -146,31 +140,6 @@ public class Vpn { } catch (RemoteException e) { Log.wtf(TAG, "Problem registering observer", e); } - // TODO: http://b/22950929 - if (userHandle == UserHandle.USER_SYSTEM) { - // Owner's VPN also needs to handle restricted users - mUserIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, - UserHandle.USER_NULL); - if (userHandle == UserHandle.USER_NULL) return; - - if (Intent.ACTION_USER_ADDED.equals(action)) { - onUserAdded(userHandle); - } else if (Intent.ACTION_USER_REMOVED.equals(action)) { - onUserRemoved(userHandle); - } - } - }; - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_USER_ADDED); - intentFilter.addAction(Intent.ACTION_USER_REMOVED); - mContext.registerReceiverAsUser( - mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); - } mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, ""); // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332 @@ -439,8 +408,8 @@ public class Vpn { } addVpnUserLocked(mUserHandle); - // If we are owner assign all Restricted Users to this VPN - if (mUserHandle == UserHandle.USER_OWNER) { + // If the user can have restricted profiles, assign all its restricted profiles to this VPN + if (canHaveRestrictedProfile(mUserHandle)) { token = Binder.clearCallingIdentity(); List<UserInfo> users; try { @@ -449,7 +418,7 @@ public class Vpn { Binder.restoreCallingIdentity(token); } for (UserInfo user : users) { - if (user.isRestricted()) { + if (user.isRestricted() && (user.restrictedProfileParentId == mUserHandle)) { addVpnUserLocked(user.id); } } @@ -457,6 +426,15 @@ public class Vpn { mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()])); } + private boolean canHaveRestrictedProfile(int userId) { + long token = Binder.clearCallingIdentity(); + try { + return UserManager.get(mContext).canHaveRestrictedProfile(userId); + } finally { + Binder.restoreCallingIdentity(token); + } + } + private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) { networkInfo.setIsAvailable(false); networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); @@ -681,12 +659,11 @@ public class Vpn { mStatusIntent = null; } - private void onUserAdded(int userHandle) { - // If the user is restricted tie them to the owner's VPN - synchronized(Vpn.this) { - UserManager mgr = UserManager.get(mContext); - UserInfo user = mgr.getUserInfo(userHandle); - if (user.isRestricted()) { + public void onUserAdded(int userHandle) { + // If the user is restricted tie them to the parent user's VPN + UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); + if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) { + synchronized(Vpn.this) { try { addVpnUserLocked(userHandle); if (mNetworkAgent != null) { @@ -700,12 +677,11 @@ public class Vpn { } } - private void onUserRemoved(int userHandle) { + public void onUserRemoved(int userHandle) { // clean up if restricted - synchronized(Vpn.this) { - UserManager mgr = UserManager.get(mContext); - UserInfo user = mgr.getUserInfo(userHandle); - if (user.isRestricted()) { + UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); + if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) { + synchronized(Vpn.this) { try { removeVpnUserLocked(userHandle); } catch (Exception e) { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 533f425e33f7..452378ff1e45 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -837,7 +837,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mPendingScreenOff && target != Display.STATE_OFF) { setScreenState(Display.STATE_OFF); mPendingScreenOff = false; - mPowerState.dismissColorFade(); } if (target == Display.STATE_ON) { @@ -911,7 +910,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // A black surface is already hiding the contents of the screen. setScreenState(Display.STATE_OFF); mPendingScreenOff = false; - mPowerState.dismissColorFade(); } else if (performScreenOffTransition && mPowerState.prepareColorFade(mContext, mColorFadeFadesConfig ? diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index be37f524eb8d..088d96e4a6e0 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -544,7 +544,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId); } } - if (physIndex > 0 && mActivePhysIndex == physIndex) { + if (mActivePhysIndex == physIndex) { return; } SurfaceControl.setActiveConfig(getDisplayTokenLocked(), physIndex); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0c884f1558fa..7b15aad7b6ca 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -27,6 +27,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.AutomaticZenRule; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; @@ -101,6 +102,7 @@ import android.widget.Toast; import com.android.internal.R; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -1172,8 +1174,8 @@ public class NotificationManagerService extends SystemService { // Don't allow client applications to cancel foreground service notis. cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, Binder.getCallingUid() == Process.SYSTEM_UID - ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL, - null); + ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, + REASON_NOMAN_CANCEL, null); } @Override @@ -1594,6 +1596,50 @@ public class NotificationManagerService extends SystemService { } @Override + public List<AutomaticZenRule> getAutomaticZenRules() throws RemoteException { + enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules"); + return mZenModeHelper.getAutomaticZenRules(); + } + + @Override + public AutomaticZenRule getAutomaticZenRule(String name) throws RemoteException { + enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule"); + return mZenModeHelper.getAutomaticZenRule(name); + } + + @Override + public boolean addOrUpdateAutomaticZenRule(AutomaticZenRule automaticZenRule) + throws RemoteException { + Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); + Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); + Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null"); + Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); + enforcePolicyAccess(Binder.getCallingUid(), "addOrUpdateZenModeRule"); + + return mZenModeHelper.addOrUpdateAutomaticZenRule(automaticZenRule, + "addOrUpdateAutomaticZenRule"); + } + + @Override + public boolean renameAutomaticZenRule(String oldName, String newName) { + Preconditions.checkNotNull(oldName, "oldName is null"); + Preconditions.checkNotNull(newName, "newName is null"); + enforcePolicyAccess(Binder.getCallingUid(), "renameAutomaticZenRule"); + + return mZenModeHelper.renameAutomaticZenRule( + oldName, newName, "renameAutomaticZenRule"); + } + + @Override + public boolean removeAutomaticZenRule(String name) throws RemoteException { + Preconditions.checkNotNull(name, "Name is null"); + // Verify that they can modify zen rules. + enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule"); + + return mZenModeHelper.removeAutomaticZenRule(name, "removeAutomaticZenRule"); + } + + @Override public void setInterruptionFilter(String pkg, int filter) throws RemoteException { enforcePolicyAccess(pkg, "setInterruptionFilter"); final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1); @@ -1641,7 +1687,30 @@ public class NotificationManagerService extends SystemService { message); } + private void enforcePolicyAccess(int uid, String method) { + if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( + android.Manifest.permission.MANAGE_NOTIFICATIONS)) { + return; + } + boolean accessAllowed = false; + String[] packages = getContext().getPackageManager().getPackagesForUid(uid); + final int packageCount = packages.length; + for (int i = 0; i < packageCount; i++) { + if (checkPolicyAccess(packages[i])) { + accessAllowed = true; + } + } + if (!accessAllowed) { + Slog.w(TAG, "Notification policy access denied calling " + method); + throw new SecurityException("Notification policy access denied"); + } + } + private void enforcePolicyAccess(String pkg, String method) { + if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission( + android.Manifest.permission.MANAGE_NOTIFICATIONS)) { + return; + } if (!checkPolicyAccess(pkg)) { Slog.w(TAG, "Notification policy access denied calling " + method); throw new SecurityException("Notification policy access denied"); @@ -1684,7 +1753,7 @@ public class NotificationManagerService extends SystemService { public boolean matchesCallFilter(Bundle extras) { enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); return mZenModeHelper.matchesCallFilter( - UserHandle.getCallingUserHandle(), + Binder.getCallingUserHandle(), extras, mRankingHelper.findExtractor(ValidateNotificationPeople.class), MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS, diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index cbe61c3da5af..4d41e3a9d734 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -21,11 +21,13 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import android.app.AppOpsManager; +import android.app.AutomaticZenRule; import android.app.NotificationManager; import android.app.NotificationManager.Policy; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.database.ContentObserver; @@ -34,6 +36,7 @@ import android.media.AudioManagerInternal; import android.media.AudioSystem; import android.media.VolumePolicy; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -62,6 +65,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.List; import java.util.Objects; /** @@ -196,6 +200,121 @@ public class ZenModeHelper { return mZenMode; } + public List<AutomaticZenRule> getAutomaticZenRules() { + List<AutomaticZenRule> rules = new ArrayList<>(); + if (mConfig == null) return rules; + for(ZenRule rule : mConfig.automaticRules.values()) { + if (canManageAutomaticZenRule(rule)) { + rules.add(createAutomaticZenRule(rule)); + } + } + return rules; + } + + public AutomaticZenRule getAutomaticZenRule(String name) { + if (mConfig == null) return null; + for(ZenRule rule : mConfig.automaticRules.values()) { + if (canManageAutomaticZenRule(rule) && rule.name.equals(name)) { + return createAutomaticZenRule(rule); + } + } + return null; + } + + public boolean addOrUpdateAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) { + if (mConfig == null) return false; + if (DEBUG) { + Log.d(TAG, "addOrUpdateAutomaticZenRule zenRule=" + automaticZenRule + + " reason=" + reason); + } + final ZenModeConfig newConfig = mConfig.copy(); + String ruleId = findMatchingRuleId(newConfig, automaticZenRule.getName()); + ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); + if (ruleId == null) { + ruleId = newConfig.newRuleId(); + rule.name = automaticZenRule.getName(); + rule.component = automaticZenRule.getOwner(); + } else { + rule = newConfig.automaticRules.get(ruleId); + if (!canManageAutomaticZenRule(rule)) { + throw new SecurityException( + "Cannot update rules not owned by your condition provider"); + } + } + if (rule.enabled != automaticZenRule.isEnabled()) { + rule.snoozing = false; + } + rule.condition = null; + rule.conditionId = automaticZenRule.getConditionId(); + rule.enabled = automaticZenRule.isEnabled(); + rule.zenMode = NotificationManager.zenModeFromInterruptionFilter( + automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF); + newConfig.automaticRules.put(ruleId, rule); + return setConfig(newConfig, reason, true); + } + + public boolean renameAutomaticZenRule(String oldName, String newName, String reason) { + if (mConfig == null) return false; + if (DEBUG) { + Log.d(TAG, "renameAutomaticZenRule oldName=" + oldName + " newName=" + newName + + " reason=" + reason); + } + final ZenModeConfig newConfig = mConfig.copy(); + String ruleId = findMatchingRuleId(newConfig, oldName); + if (ruleId == null) { + return false; + } else { + ZenRule rule = newConfig.automaticRules.get(ruleId); + if (!canManageAutomaticZenRule(rule)) { + throw new SecurityException( + "Cannot update rules not owned by your condition provider"); + } + rule.name = newName; + return setConfig(newConfig, reason, true); + } + } + + public boolean removeAutomaticZenRule(String name, String reason) { + if (mConfig == null) return false; + final ZenModeConfig newConfig = mConfig.copy(); + String ruleId = findMatchingRuleId(newConfig, name); + if (ruleId != null) { + ZenRule rule = newConfig.automaticRules.get(ruleId); + if (canManageAutomaticZenRule(rule)) { + newConfig.automaticRules.remove(ruleId); + if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + name + " reason=" + reason); + } else { + throw new SecurityException( + "Cannot delete rules not owned by your condition provider"); + } + } + return setConfig(newConfig, reason, true); + } + + public boolean canManageAutomaticZenRule(ZenRule rule) { + if (mContext.checkCallingPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS) + == PackageManager.PERMISSION_GRANTED) { + return true; + } else { + String[] packages = mContext.getPackageManager().getPackagesForUid( + Binder.getCallingUid()); + if (packages != null) { + final int packageCount = packages.length; + for (int i = 0; i < packageCount; i++) { + if (packages[i].equals(rule.component.getPackageName())) { + return true; + } + } + } + return false; + } + } + + private AutomaticZenRule createAutomaticZenRule(ZenRule rule) { + return new AutomaticZenRule(rule.name, rule.component, rule.conditionId, + NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled); + } + public void setManualZenMode(int zenMode, Uri conditionId, String reason) { setManualZenMode(zenMode, conditionId, reason, true /*setRingerMode*/); } @@ -225,6 +344,15 @@ public class ZenModeHelper { setConfig(newConfig, reason, setRingerMode); } + private String findMatchingRuleId(ZenModeConfig config, String ruleName) { + for (String ruleId : config.automaticRules.keySet()) { + if (config.automaticRules.get(ruleId).name.equals(ruleName)) { + return ruleId; + } + } + return null; + } + public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mZenMode="); pw.println(Global.zenModeToString(mZenMode)); @@ -248,8 +376,9 @@ public class ZenModeHelper { } pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s," + "events=%s,reminders=%s)\n", - config.allowCalls, config.allowCallsFrom, config.allowRepeatCallers, - config.allowMessages, config.allowMessagesFrom, + config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom), + config.allowRepeatCallers, config.allowMessages, + ZenModeConfig.sourceToString(config.allowMessagesFrom), config.allowEvents, config.allowReminders); pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule); if (config.automaticRules.isEmpty()) return; @@ -271,7 +400,7 @@ public class ZenModeHelper { } config.manualRule = null; // don't restore the manual rule if (config.automaticRules != null) { - for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) { + for (ZenRule automaticRule : config.automaticRules.values()) { // don't restore transient state from restored automatic rules automaticRule.snoozing = false; automaticRule.condition = null; @@ -318,36 +447,41 @@ public class ZenModeHelper { } private boolean setConfig(ZenModeConfig config, String reason, boolean setRingerMode) { - if (config == null || !config.isValid()) { - Log.w(TAG, "Invalid config in setConfig; " + config); - return false; - } - if (config.user != mUser) { - // simply store away for background users + final long identity = Binder.clearCallingIdentity(); + try { + if (config == null || !config.isValid()) { + Log.w(TAG, "Invalid config in setConfig; " + config); + return false; + } + if (config.user != mUser) { + // simply store away for background users + mConfigs.put(config.user, config); + if (DEBUG) Log.d(TAG, "setConfig: store config for user " + config.user); + return true; + } + mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config mConfigs.put(config.user, config); - if (DEBUG) Log.d(TAG, "setConfig: store config for user " + config.user); + if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable()); + ZenLog.traceConfig(reason, mConfig, config); + final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig), + getNotificationPolicy(config)); + mConfig = config; + if (config.equals(mConfig)) { + dispatchOnConfigChanged(); + } + if (policyChanged){ + dispatchOnPolicyChanged(); + } + final String val = Integer.toString(mConfig.hashCode()); + Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val); + if (!evaluateZenMode(reason, setRingerMode)) { + applyRestrictions(); // evaluateZenMode will also apply restrictions if changed + } + mConditions.evaluateConfig(config, true /*processSubscriptions*/); return true; + } finally { + Binder.restoreCallingIdentity(identity); } - mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config - mConfigs.put(config.user, config); - if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable()); - ZenLog.traceConfig(reason, mConfig, config); - final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig), - getNotificationPolicy(config)); - mConfig = config; - if (config.equals(mConfig)) { - dispatchOnConfigChanged(); - } - if (policyChanged){ - dispatchOnPolicyChanged(); - } - final String val = Integer.toString(mConfig.hashCode()); - Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val); - if (!evaluateZenMode(reason, setRingerMode)) { - applyRestrictions(); // evaluateZenMode will also apply restrictions if changed - } - mConditions.evaluateConfig(config, true /*processSubscriptions*/); - return true; } private int getZenModeSetting() { @@ -505,6 +639,7 @@ public class ZenModeHelper { .getString(R.string.zen_mode_default_weeknights_name); rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); rule1.zenMode = Global.ZEN_MODE_ALARMS; + rule1.component = ScheduleConditionProvider.COMPONENT; config.automaticRules.put(config.newRuleId(), rule1); final ScheduleInfo weekends = new ScheduleInfo(); @@ -518,6 +653,7 @@ public class ZenModeHelper { .getString(R.string.zen_mode_default_weekends_name); rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends); rule2.zenMode = Global.ZEN_MODE_ALARMS; + rule2.component = ScheduleConditionProvider.COMPONENT; config.automaticRules.put(config.newRuleId(), rule2); } @@ -532,6 +668,7 @@ public class ZenModeHelper { rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name); rule.conditionId = ZenModeConfig.toEventConditionId(events); rule.zenMode = Global.ZEN_MODE_ALARMS; + rule.component = EventConditionProvider.COMPONENT; config.automaticRules.put(config.newRuleId(), rule); } @@ -572,6 +709,7 @@ public class ZenModeHelper { rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule); rule.zenMode = v1.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + rule.component = ScheduleConditionProvider.COMPONENT; rt.automaticRules.put(rt.newRuleId(), rule); } else { Log.i(TAG, "No existing V1 downtime found, generating default schedules"); diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index f292c9c4c3d8..d8676167497f 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -31,6 +31,21 @@ import com.android.server.SystemService; public final class Installer extends SystemService { private static final String TAG = "Installer"; + /* *************************************************************************** + * IMPORTANT: These values are passed to native code. Keep them in sync with + * frameworks/native/cmds/installd/installd.h + * **************************************************************************/ + /** Application should be visible to everyone */ + public static final int DEXOPT_PUBLIC = 1 << 1; + /** Application wants to run in VM safe mode */ + public static final int DEXOPT_SAFEMODE = 1 << 2; + /** Application wants to allow debugging of its code */ + public static final int DEXOPT_DEBUGGABLE = 1 << 3; + /** The system boot has finished */ + public static final int DEXOPT_BOOTCOMPLETE = 1 << 4; + /** Run the application with the JIT compiler */ + public static final int DEXOPT_USEJIT = 1 << 5; + private final InstallerConnection mInstaller; public Installer(Context context) { @@ -75,39 +90,24 @@ public final class Installer extends SystemService { return mInstaller.execute(builder.toString()); } - public int dexopt(String apkPath, int uid, boolean isPublic, - String instructionSet, int dexoptNeeded) { - return dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded, true); - } - - public int dexopt(String apkPath, int uid, boolean isPublic, - String instructionSet, int dexoptNeeded, boolean bootComplete) { + public int dexopt(String apkPath, int uid, String instructionSet, + int dexoptNeeded, int dexFlags) { if (!isValidInstructionSet(instructionSet)) { Slog.e(TAG, "Invalid instruction set: " + instructionSet); return -1; } - return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded, - bootComplete); - } - - public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, - String instructionSet, int dexoptNeeded, boolean vmSafeMode, - boolean debuggable, @Nullable String outputPath) { - return dexopt(apkPath, uid, isPublic, pkgName, instructionSet, dexoptNeeded, vmSafeMode, - debuggable, outputPath, true); + return mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags); } - public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, - String instructionSet, int dexoptNeeded, boolean vmSafeMode, - boolean debuggable, @Nullable String outputPath, boolean bootComplete) { + public int dexopt(String apkPath, int uid, String pkgName, String instructionSet, + int dexoptNeeded, @Nullable String outputPath, int dexFlags) { if (!isValidInstructionSet(instructionSet)) { Slog.e(TAG, "Invalid instruction set: " + instructionSet); return -1; } - return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, - instructionSet, dexoptNeeded, vmSafeMode, - debuggable, outputPath, bootComplete); + return mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, + outputPath, dexFlags); } public int idmap(String targetApkPath, String overlayApkPath, int uid) { diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index b692def44153..6c6871fd8dfd 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -35,6 +35,11 @@ import java.util.List; import dalvik.system.DexFile; +import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; +import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; +import static com.android.server.pm.Installer.DEXOPT_PUBLIC; +import static com.android.server.pm.Installer.DEXOPT_SAFEMODE; +import static com.android.server.pm.Installer.DEXOPT_USEJIT; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; @@ -71,7 +76,8 @@ final class PackageDexOptimizer { * {@link PackageManagerService#mInstallLock}. */ int performDexOpt(PackageParser.Package pkg, String[] instructionSets, - boolean forceDex, boolean defer, boolean inclDependencies, boolean bootComplete) { + boolean forceDex, boolean defer, boolean inclDependencies, + boolean bootComplete, boolean useJit) { ArraySet<String> done; if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) { done = new ArraySet<String>(); @@ -86,7 +92,8 @@ final class PackageDexOptimizer { mDexoptWakeLock.acquire(); } try { - return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete, done); + return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete, + useJit, done); } finally { if (useLock) { mDexoptWakeLock.release(); @@ -96,7 +103,8 @@ final class PackageDexOptimizer { } private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets, - boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) { + boolean forceDex, boolean defer, boolean bootComplete, boolean useJit, + ArraySet<String> done) { final String[] instructionSets = targetInstructionSets != null ? targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo); @@ -104,11 +112,11 @@ final class PackageDexOptimizer { done.add(pkg.packageName); if (pkg.usesLibraries != null) { performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, - bootComplete, done); + bootComplete, useJit, done); } if (pkg.usesOptionalLibraries != null) { performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer, - bootComplete, done); + bootComplete, useJit, done); } } @@ -175,11 +183,17 @@ final class PackageDexOptimizer { Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg=" + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable - + " oatDir = " + oatDir + " bootComplete=" + bootComplete); + + " oatDir = " + oatDir + " bootComplete=" + bootComplete + + " useJit=" + useJit); final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + final int dexFlags = + (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0) + | (vmSafeMode ? DEXOPT_SAFEMODE : 0) + | (debuggable ? DEXOPT_DEBUGGABLE : 0) + | (bootComplete ? DEXOPT_BOOTCOMPLETE : 0) + | (useJit ? DEXOPT_USEJIT : 0); final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid, - !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet, - dexoptNeeded, vmSafeMode, debuggable, oatDir, bootComplete); + pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir, dexFlags); // Dex2oat might fail due to compiler / verifier errors. We soldier on // regardless, and attempt to interpret the app as a safety net. @@ -236,12 +250,13 @@ final class PackageDexOptimizer { } private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets, - boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) { + boolean forceDex, boolean defer, boolean bootComplete, boolean useJit, + ArraySet<String> done) { for (String libName : libs) { PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary( libName); if (libPkg != null && !done.contains(libName)) { - performDexOptLI(libPkg, instructionSets, forceDex, defer, bootComplete, done); + performDexOptLI(libPkg, instructionSets, forceDex, defer, bootComplete, useJit, done); } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index af0a73efabc5..c729e28dae82 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -75,6 +75,7 @@ import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME; import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; import static com.android.internal.util.ArrayUtils.appendInt; +import static com.android.server.pm.Installer.DEXOPT_PUBLIC; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; @@ -2015,7 +2016,8 @@ public class PackageManagerService extends IPackageManager.Stub { int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false); if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { alreadyDexOpted.add(lib); - mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false); + mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet, + dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/); } } catch (FileNotFoundException e) { Slog.w(TAG, "Library not found: " + lib); @@ -2063,7 +2065,8 @@ public class PackageManagerService extends IPackageManager.Stub { try { int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false); if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { - mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false); + mInstaller.dexopt(path, Process.SYSTEM_UID, dexCodeInstructionSet, + dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/); } } catch (FileNotFoundException e) { Slog.w(TAG, "Jar not found: " + path); @@ -6156,41 +6159,6 @@ public class PackageManagerService extends IPackageManager.Stub { it.remove(); } } - // Give priority to system apps. - for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) { - PackageParser.Package pkg = it.next(); - if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "Adding system app " + sortedPkgs.size() + ": " + pkg.packageName); - } - sortedPkgs.add(pkg); - it.remove(); - } - } - // Give priority to updated system apps. - for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) { - PackageParser.Package pkg = it.next(); - if (pkg.isUpdatedSystemApp()) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "Adding updated system app " + sortedPkgs.size() + ": " + pkg.packageName); - } - sortedPkgs.add(pkg); - it.remove(); - } - } - // Give priority to apps that listen for boot complete. - intent = new Intent(Intent.ACTION_BOOT_COMPLETED); - pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM); - for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) { - PackageParser.Package pkg = it.next(); - if (pkgNames.contains(pkg.packageName)) { - if (DEBUG_DEXOPT) { - Log.i(TAG, "Adding boot app " + sortedPkgs.size() + ": " + pkg.packageName); - } - sortedPkgs.add(pkg); - it.remove(); - } - } // Filter out packages that aren't recently used. filterRecentlyUsedApps(pkgs); // Add all remaining apps. @@ -6283,7 +6251,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mInstallLock) { mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */, false /* force dex */, false /* defer */, true /* include dependencies */, - false /* boot complete */); + false /* boot complete */, false /*useJit*/); } } @@ -6343,7 +6311,7 @@ public class PackageManagerService extends IPackageManager.Stub { final String[] instructionSets = new String[] { targetInstructionSet }; int result = mPackageDexOptimizer.performDexOpt(p, instructionSets, false /* forceDex */, false /* defer */, true /* inclDependencies */, - true /* boot complete */); + true /* boot complete */, false /*useJit*/); return result == PackageDexOptimizer.DEX_OPT_PERFORMED; } } finally { @@ -6394,7 +6362,7 @@ public class PackageManagerService extends IPackageManager.Stub { final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets, true /*forceDex*/, false /* defer */, true /* inclDependencies */, - true /* boot complete */); + true /* boot complete */, false /*useJit*/); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) { @@ -7211,7 +7179,7 @@ public class PackageManagerService extends IPackageManager.Stub { int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */, - (scanFlags & SCAN_BOOTING) == 0); + (scanFlags & SCAN_BOOTING) == 0, false /*useJit*/); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { @@ -7292,7 +7260,7 @@ public class PackageManagerService extends IPackageManager.Stub { int result = mPackageDexOptimizer.performDexOpt(clientPkg, null /* instruction sets */, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false, - (scanFlags & SCAN_BOOTING) == 0); + (scanFlags & SCAN_BOOTING) == 0, false /*useJit*/); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI failed to dexopt clientLibPkgs"); @@ -7916,7 +7884,7 @@ public class PackageManagerService extends IPackageManager.Stub { int result = mPackageDexOptimizer.performDexOpt(ps.pkg, null /* instruction sets */, forceDexOpt, deferDexOpt, true, - bootComplete); + bootComplete, false /*useJit*/); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { @@ -12607,8 +12575,7 @@ public class PackageManagerService extends IPackageManager.Stub { int result = mPackageDexOptimizer .performDexOpt(pkg, null /* instruction sets */, false /* forceDex */, false /* defer */, false /* inclDependencies */, - true /* boot complete */); - + true /*bootComplete*/, false /*useJit*/); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 1924bab6fac6..de106a1d0d3c 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import android.accounts.Account; import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityManager; @@ -63,6 +64,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsService; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; +import com.android.server.accounts.AccountManagerService; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -129,7 +131,7 @@ public class UserManagerService extends IUserManager.Stub { private static final int MIN_USER_ID = 10; - private static final int USER_VERSION = 5; + private static final int USER_VERSION = 6; private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms @@ -406,6 +408,24 @@ public class UserManagerService extends IUserManager.Stub { } } + @Override + public boolean canHaveRestrictedProfile(int userId) { + checkManageUsersPermission("canHaveRestrictedProfile"); + synchronized (mPackagesLock) { + final UserInfo userInfo = getUserInfoLocked(userId); + if (userInfo == null || !userInfo.canHaveProfile()) { + return false; + } + if (!userInfo.isAdmin()) { + return false; + } + } + DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService( + Context.DEVICE_POLICY_SERVICE); + // restricted profile can be created if there is no DO set and the admin user has no PO + return dpm.getDeviceOwner() == null && dpm.getProfileOwnerAsUser(userId) == null; + } + /* * Should be locked on mUsers before calling this. */ @@ -846,6 +866,20 @@ public class UserManagerService extends IUserManager.Stub { userVersion = 5; } + if (userVersion < 6) { + final boolean splitSystemUser = UserManager.isSplitSystemUser(); + for (int i = 0; i < mUsers.size(); i++) { + UserInfo user = mUsers.valueAt(i); + // In non-split mode, only user 0 can have restricted profiles + if (!splitSystemUser && user.isRestricted() + && (user.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID)) { + user.restrictedProfileParentId = UserHandle.USER_SYSTEM; + scheduleWriteUserLocked(user); + } + } + userVersion = 6; + } + if (userVersion < USER_VERSION) { Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to " + USER_VERSION); @@ -1386,6 +1420,25 @@ public class UserManagerService extends IUserManager.Stub { } /** + * @hide + */ + public UserInfo createRestrictedProfile(String name, int parentUserId) { + checkManageUsersPermission("setupRestrictedProfile"); + final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId); + if (user == null) { + return null; + } + setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id); + // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise + // the putIntForUser() will fail. + android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(), + android.provider.Settings.Secure.LOCATION_MODE, + android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id); + setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id); + return user; + } + + /** * Find the current guest user. If the Guest user is partial, * then do not include it in the results as it is about to die. */ diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 04d382d6871f..c265000f13f5 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2003,6 +2003,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_SYSTEM_DIALOG: case TYPE_VOLUME_OVERLAY: case TYPE_PRIVATE_PRESENTATION: + case TYPE_DOCK_DIVIDER: break; } @@ -2104,6 +2105,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_WALLPAPER: // wallpaper is at the bottom, though the window manager may move it. return 2; + case TYPE_DOCK_DIVIDER: + return 2; case TYPE_PHONE: return 3; case TYPE_SEARCH_BAR: @@ -2271,6 +2274,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_WALLPAPER: case TYPE_DREAM: case TYPE_KEYGUARD_SCRIM: + case TYPE_DOCK_DIVIDER: return false; default: // Hide only windows below the keyguard host window. @@ -4428,6 +4432,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (attrs.type == TYPE_STATUS_BAR) { if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { mForceStatusBarFromKeyguard = true; + mShowingLockscreen = true; } if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) { mForceStatusBarTransparent = true; @@ -4448,9 +4453,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mForceStatusBar = true; } } - if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { - mShowingLockscreen = true; - } if (attrs.type == TYPE_DREAM) { // If the lockscreen was showing when the dream started then wait // for the dream to draw before hiding the lockscreen. diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index 5d0193108891..25d646d2bb3b 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -28,5 +28,5 @@ public interface StatusBarManagerInternal { void showScreenPinningRequest(); void showAssistDisclosure(); void startAssist(Bundle args); - void onCameraLaunchGestureDetected(); + void onCameraLaunchGestureDetected(int source); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 11a16394a502..19b03d5e56cd 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -178,10 +178,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public void onCameraLaunchGestureDetected() { + public void onCameraLaunchGestureDetected(int source) { if (mBar != null) { try { - mBar.onCameraLaunchGestureDetected(); + mBar.onCameraLaunchGestureDetected(source); } catch (RemoteException e) { } } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 192b168122bd..cc51d204e98d 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -1003,19 +1003,36 @@ public class AppTransition implements Dump { return prepareThumbnailAnimation(a, appWidth, appHeight, transit); } - private Animation createRelaunchAnimation(int appWidth, int appHeight) { + private Animation createRelaunchAnimation(int appWidth, int appHeight, + Rect containingFrame) { getDefaultNextAppTransitionStartRect(mTmpFromClipRect); final int left = mTmpFromClipRect.left; final int top = mTmpFromClipRect.top; mTmpFromClipRect.offset(-left, -top); mTmpToClipRect.set(0, 0, appWidth, appHeight); AnimationSet set = new AnimationSet(true); - ClipRectAnimation clip = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect); - TranslateAnimation translate = new TranslateAnimation(left, 0, top, 0); - clip.setInterpolator(mDecelerateInterpolator); - set.addAnimation(clip); + float fromWidth = mTmpFromClipRect.width(); + float toWidth = mTmpToClipRect.width(); + float fromHeight = mTmpFromClipRect.height(); + float toHeight = mTmpToClipRect.height(); + if (fromWidth <= toWidth && fromHeight <= toHeight) { + // The final window is larger in both dimensions than current window (e.g. we are + // maximizing), so we can simply unclip the new window and there will be no disappearing + // frame. + set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect)); + } else { + // The disappearing window has one larger dimension. We need to apply scaling, so the + // first frame of the entry animation matches the old window. + set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1)); + } + + // We might not be going exactly full screen, but instead be aligned under the status bar. + // We need to take this into account when creating the translate animation. + TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left, + 0, top - containingFrame.top, 0); set.addAnimation(translate); set.setDuration(DEFAULT_APP_TRANSITION_DURATION); + set.setZAdjustment(Animation.ZORDER_TOP); return set; } @@ -1056,7 +1073,12 @@ public class AppTransition implements Dump { + " anim=" + a + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3)); } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) { - a = createRelaunchAnimation(appWidth, appHeight); + a = createRelaunchAnimation(appWidth, appHeight, containingFrame); + if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, + "applyAnimation:" + + " anim=" + a + " nextAppTransition=" + mNextAppTransition + + " transit=" + appTransitionToString(transit) + + " Callers=" + Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { a = loadAnimationRes(mNextAppTransitionPackage, enter ? mNextAppTransitionEnter : mNextAppTransitionExit); @@ -1077,6 +1099,7 @@ public class AppTransition implements Dump { if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "applyAnimation:" + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL" + + " transit=" + appTransitionToString(transit) + " Callers=" + Debug.getCallers(3)); } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) { a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index ff216c5c763d..5a1ed582358c 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -74,10 +74,6 @@ class AppWindowToken extends WindowToken { // case do not clear allDrawn until the animation completes. boolean deferClearAllDrawn; - // Is this token going to be hidden in a little while? If so, it - // won't be taken into account for setting the screen orientation. - boolean willBeHidden; - // Is this window's surface needed? This is almost like hidden, except // it will sometimes be true a little earlier: when the token has // been shown, but is still waiting for its app transition to execute @@ -321,7 +317,6 @@ class AppWindowToken extends WindowToken { pw.print(" requestedOrientation="); pw.println(requestedOrientation); pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested); pw.print(" clientHidden="); pw.print(clientHidden); - pw.print(" willBeHidden="); pw.print(willBeHidden); pw.print(" reportedDrawn="); pw.print(reportedDrawn); pw.print(" reportedVisible="); pw.println(reportedVisible); if (paused) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index cb0dba833095..745874cba3f5 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -16,11 +16,13 @@ package com.android.server.wm; +import static android.app.ActivityManager.DOCKED_STACK_ID; import static android.app.ActivityManager.HOME_STACK_ID; import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerService.TAG; import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP; +import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH; import android.graphics.Rect; import android.graphics.Region; @@ -111,6 +113,8 @@ class DisplayContent { /** Remove this display when animation on it has completed. */ boolean mDeferredRemoval; + final DockedStackDividerController mDividerControllerLocked; + /** * @param display May not be null. * @param service You know. @@ -122,6 +126,8 @@ class DisplayContent { display.getMetrics(mDisplayMetrics); isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY; mService = service; + initializeDisplayBaseInfo(); + mDividerControllerLocked = new DockedStackDividerController(service.mContext, this); } int getDisplayId() { @@ -187,6 +193,21 @@ class DisplayContent { } } + void initializeDisplayBaseInfo() { + synchronized(mDisplaySizeLock) { + // Bootstrap the default logical display from the display manager. + final DisplayInfo newDisplayInfo = + mService.mDisplayManagerInternal.getDisplayInfo(mDisplayId); + if (newDisplayInfo != null) { + mDisplayInfo.copyFrom(newDisplayInfo); + } + mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth; + mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight; + mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi; + mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight); + } + } + void getLogicalDisplayRect(Rect out) { // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. final int orientation = mDisplayInfo.rotation; @@ -242,7 +263,7 @@ class DisplayContent { for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { final Task task = tasks.get(taskNdx); task.getBounds(mTmpRect); - if (task.inFreeformWorkspace() && mTmpRect.contains(x, y)) { + if (mTmpRect.contains(x, y)) { return task.mTaskId; } } @@ -251,10 +272,10 @@ class DisplayContent { } /** - * Find the id of the task whose outside touch area (for resizing) (x, y) - * falls within. Returns -1 if the touch doesn't fall into a resizing area. + * Find the window whose outside touch area (for resizing) (x, y) falls within. + * Returns null if the touch doesn't fall into a resizing area. */ - int taskIdForControlPoint(int x, int y) { + WindowState findWindowForControlPoint(int x, int y) { final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics); for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { TaskStack stack = mStacks.get(stackNdx); @@ -265,22 +286,31 @@ class DisplayContent { for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { final Task task = tasks.get(taskNdx); if (task.isFullscreen()) { - return -1; + return null; } - task.getBounds(mTmpRect); - mTmpRect.inset(-delta, -delta); - if (mTmpRect.contains(x, y)) { - mTmpRect.inset(delta, delta); - if (!mTmpRect.contains(x, y)) { - return task.mTaskId; + + // We need to use the visible frame on the window for any touch-related + // tests. Can't use the task's bounds because the original task bounds + // might be adjusted to fit the content frame. (One example is when the + // task is put to top-left quadrant, the actual visible frame would not + // start at (0,0) after it's adjusted for the status bar.) + WindowState win = task.getTopAppMainWindow(); + if (win != null) { + win.getVisibleBounds(mTmpRect, !BOUNDS_FOR_TOUCH); + mTmpRect.inset(-delta, -delta); + if (mTmpRect.contains(x, y)) { + mTmpRect.inset(delta, delta); + if (!mTmpRect.contains(x, y)) { + return win; + } + // User touched inside the task. No need to look further, + // focus transfer will be handled in ACTION_UP. + return null; } - // User touched inside the task. No need to look further, - // focus transfer will be handled in ACTION_UP. - return -1; } } } - return -1; + return null; } void setTouchExcludeRegion(Task focusedTask) { @@ -552,4 +582,14 @@ class DisplayContent { public String toString() { return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks; } + + TaskStack getDockedStackLocked() { + for (int i = mStacks.size() - 1; i >= 0; i--) { + TaskStack stack = mStacks.get(i); + if (stack.mStackId == DOCKED_STACK_ID && stack.isVisibleLocked()) { + return stack; + } + } + return null; + } } diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java new file mode 100644 index 000000000000..8c5d319439ba --- /dev/null +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.app.ActivityManager.DOCKED_STACK_ID; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; +import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; +import static android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING; +import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; +import static com.android.server.wm.TaskStack.DOCKED_BOTTOM; +import static com.android.server.wm.TaskStack.DOCKED_INVALID; +import static com.android.server.wm.TaskStack.DOCKED_LEFT; +import static com.android.server.wm.TaskStack.DOCKED_RIGHT; +import static com.android.server.wm.TaskStack.DOCKED_TOP; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.os.RemoteException; +import android.util.Slog; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; + +/** + * Controls showing and hiding of a docked stack divider on the display. + */ +public class DockedStackDividerController implements View.OnTouchListener { + private static final String TAG = "DockedStackDivider"; + private final Context mContext; + private final int mDividerWidth; + private final DisplayContent mDisplayContent; + private View mView; + private Rect mTmpRect = new Rect(); + private Rect mLastResizeRect = new Rect(); + private int mStartX; + private int mStartY; + private TaskStack mTaskStack; + private Rect mOriginalRect = new Rect(); + private int mDockSide; + + + DockedStackDividerController(Context context, DisplayContent displayContent) { + mContext = context; + mDisplayContent = displayContent; + mDividerWidth = context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.docked_stack_divider_thickness); + } + + private void addDivider() { + View view = LayoutInflater.from(mContext).inflate( + com.android.internal.R.layout.docked_stack_divider, null); + view.setOnTouchListener(this); + WindowManagerGlobal manager = WindowManagerGlobal.getInstance(); + WindowManager.LayoutParams params = new WindowManager.LayoutParams( + mDividerWidth, MATCH_PARENT, TYPE_DOCK_DIVIDER, + FLAG_TOUCHABLE_WHEN_WAKING | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL + | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH, + PixelFormat.OPAQUE); + params.setTitle(TAG); + manager.addView(view, params, mDisplayContent.getDisplay(), null); + mView = view; + } + + private void removeDivider() { + mView.setOnTouchListener(null); + WindowManagerGlobal manager = WindowManagerGlobal.getInstance(); + manager.removeView(mView, true /* immediate */); + mView = null; + } + + boolean hasDivider() { + return mView != null; + } + + void update() { + TaskStack stack = mDisplayContent.getDockedStackLocked(); + if (stack != null && mView == null) { + addDivider(); + } else if (stack == null && mView != null) { + removeDivider(); + } + } + + int getWidth() { + return mDividerWidth; + } + + void positionDockedStackedDivider(Rect frame) { + TaskStack stack = mDisplayContent.getDockedStackLocked(); + if (stack == null) { + // Unfortunately we might end up with still having a divider, even though the underlying + // stack was already removed. This is because we are on AM thread and the removal of the + // divider was deferred to WM thread and hasn't happened yet. + return; + } + final @TaskStack.DockSide int side = stack.getDockSide(); + stack.getBounds(mTmpRect); + switch (side) { + case DOCKED_LEFT: + frame.set(mTmpRect.right, frame.top, mTmpRect.right + frame.width(), frame.bottom); + break; + case DOCKED_TOP: + frame.set(frame.left, mTmpRect.bottom, mTmpRect.right, + mTmpRect.bottom + frame.height()); + break; + case DOCKED_RIGHT: + frame.set(mTmpRect.left - frame.width(), frame.top, mTmpRect.left, frame.bottom); + break; + case DOCKED_BOTTOM: + frame.set(frame.left, mTmpRect.top - frame.height(), frame.right, mTmpRect.top); + break; + } + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + final int action = event.getAction() & MotionEvent.ACTION_MASK; + switch (action) { + case MotionEvent.ACTION_DOWN: + // We use raw values, because getX/Y() would give us results relative to the + // dock divider bounds. + mStartX = (int) event.getRawX(); + mStartY = (int) event.getRawY(); + synchronized (mDisplayContent.mService.mWindowMap) { + mTaskStack = mDisplayContent.getDockedStackLocked(); + mTaskStack.getBounds(mOriginalRect); + mDockSide = mTaskStack.getDockSide(); + } + break; + case MotionEvent.ACTION_MOVE: + if (mTaskStack != null) { + resizeStack(event); + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mTaskStack = null; + mDockSide = TaskStack.DOCKED_INVALID; + break; + } + return true; + } + + private void resizeStack(MotionEvent event) { + mTmpRect.set(mOriginalRect); + final int deltaX = (int) event.getRawX() - mStartX; + final int deltaY = (int) event.getRawY() - mStartY; + switch (mDockSide) { + case DOCKED_LEFT: + mTmpRect.right += deltaX; + break; + case DOCKED_TOP: + mTmpRect.bottom += deltaY; + break; + case DOCKED_RIGHT: + mTmpRect.left += deltaX; + break; + case DOCKED_BOTTOM: + mTmpRect.top += deltaY; + break; + } + if (mTmpRect.equals(mLastResizeRect)) { + return; + } + mLastResizeRect.set(mTmpRect); + try { + mDisplayContent.mService.mActivityManager.resizeStack(DOCKED_STACK_ID, mTmpRect); + } catch (RemoteException e) { + } + } + + boolean isResizing() { + return mTaskStack != null; + } + + int getWidthAdjustment() { + return getWidth() / 2; + } +} diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 4244205aabf8..6c391ade60cc 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH; import android.app.ActivityManagerNative; import android.graphics.Rect; @@ -170,7 +171,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { private void addInputWindowHandleLw(final InputWindowHandle inputWindowHandle, final WindowState child, int flags, final int type, final boolean isVisible, - final boolean hasFocus, final boolean hasWallpaper) { + final boolean hasFocus, final boolean hasWallpaper, DisplayContent displayContent) { // Add a window to our list of input windows. inputWindowHandle.name = child.toString(); final boolean modal = (flags & (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL @@ -202,6 +203,20 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { inputWindowHandle.frameTop = frame.top; inputWindowHandle.frameRight = frame.right; inputWindowHandle.frameBottom = frame.bottom; + if (child.mAttrs.type == TYPE_DOCK_DIVIDER) { + // We need to determine if the divider is horizontal or vertical and adjust its handle + // frame accordingly. + int adjustment = displayContent.mDividerControllerLocked.getWidthAdjustment(); + if (inputWindowHandle.frameRight - inputWindowHandle.frameLeft > + inputWindowHandle.frameTop - inputWindowHandle.frameBottom) { + // Horizontal divider. + inputWindowHandle.frameTop -= adjustment; + inputWindowHandle.frameBottom += adjustment; + } else { + inputWindowHandle.frameLeft -= adjustment; + inputWindowHandle.frameRight += adjustment; + } + } if (child.mGlobalScale != 1) { // If we are scaling the window, input coordinates need @@ -277,7 +292,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { final int numDisplays = mService.mDisplayContents.size(); final WallpaperController wallpaperController = mService.mWallpaperControllerLocked; for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { - WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList(); + final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx); + final WindowList windows = displayContent.getWindowList(); for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { final WindowState child = windows.get(winNdx); final InputChannel inputChannel = child.mInputChannel; @@ -315,7 +331,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { } addInputWindowHandleLw(inputWindowHandle, child, flags, type, isVisible, hasFocus, - hasWallpaper); + hasWallpaper, displayContent); } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 4541dd6030b6..1f986dd90b10 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -16,9 +16,12 @@ package com.android.server.wm; +import static android.app.ActivityManager.DOCKED_STACK_ID; +import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION; import static com.android.server.wm.WindowManagerService.TAG; import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE; import static com.android.server.wm.WindowManagerService.DEBUG_STACK; +import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK; import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID; import android.content.res.Configuration; @@ -244,8 +247,32 @@ class Task implements DimLayer.DimLayerUser { return true; } + /** Return true if the current bound can get outputted to the rest of the system as-is. */ + private boolean useCurrentBounds() { + final DisplayContent displayContent = mStack.getDisplayContent(); + if (mFullscreen + || mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID + || mStack.mStackId == DOCKED_STACK_ID + || displayContent == null + || displayContent.getDockedStackLocked() != null) { + return true; + } + return false; + } + + /** Bounds of the task with other system factors taken into consideration. */ void getBounds(Rect out) { - out.set(mBounds); + if (useCurrentBounds()) { + // No need to adjust the output bounds if fullscreen or the docked stack is visible + // since it is already what we want to represent to the rest of the system. + out.set(mBounds); + return; + } + + // The bounds has been adjusted to accommodate for a docked stack, but the docked stack + // is not currently visible. Go ahead a represent it as fullscreen to the rest of the + // system. + mStack.getDisplayContent().getLogicalDisplayRect(out); } void setDragResizing(boolean dragResizing) { @@ -273,7 +300,13 @@ class Task implements DimLayer.DimLayerUser { // this happens, so update the task bounds so it stays in the same place. mTmpRect2.set(mBounds); displayContent.rotateBounds(mRotation, newRotation, mTmpRect2); - setBounds(mTmpRect2, mOverrideConfig); + if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) { + // Post message to inform activity manager of the bounds change simulating + // a one-way call. We do this to prevent a deadlock between window manager + // lock and activity manager lock been held. + mService.mH.sendMessage(mService.mH.obtainMessage( + RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds)); + } } /** Updates the dim layer bounds, recreating it if needed. */ @@ -432,9 +465,20 @@ class Task implements DimLayer.DimLayerUser { return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID; } + WindowState getTopAppMainWindow() { + final int tokensCount = mAppTokens.size(); + return tokensCount > 0 ? mAppTokens.get(tokensCount - 1).findMainWindow() : null; + } + @Override public boolean isFullscreen() { - return mFullscreen; + if (useCurrentBounds()) { + return mFullscreen; + } + // The bounds has been adjusted to accommodate for a docked stack, but the docked stack + // is not currently visible. Go ahead a represent it as fullscreen to the rest of the + // system. + return true; } @Override diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index a94be834897e..df2e5e80b59b 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -22,6 +22,7 @@ import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.RESIZE_MODE_FORCED; import static android.app.ActivityManager.RESIZE_MODE_USER; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.server.wm.WindowManagerService.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP; @@ -33,14 +34,16 @@ import android.graphics.Rect; import android.os.Looper; import android.os.Process; import android.os.RemoteException; +import android.os.Trace; import android.util.DisplayMetrics; import android.util.Slog; +import android.view.Choreographer; import android.view.Display; import android.view.DisplayInfo; import android.view.InputChannel; import android.view.InputDevice; import android.view.InputEvent; -import android.view.InputEventReceiver; +import android.view.BatchedInputEventReceiver; import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.WindowManager; @@ -96,15 +99,17 @@ class TaskPositioner implements DimLayer.DimLayerUser { private float mStartDragY; @CtrlType private int mCtrlType = CTRL_NONE; + private boolean mDragEnded = false; InputChannel mServerChannel; InputChannel mClientChannel; InputApplicationHandle mDragApplicationHandle; InputWindowHandle mDragWindowHandle; - private final class WindowPositionerEventReceiver extends InputEventReceiver { - public WindowPositionerEventReceiver(InputChannel inputChannel, Looper looper) { - super(inputChannel, looper); + private final class WindowPositionerEventReceiver extends BatchedInputEventReceiver { + public WindowPositionerEventReceiver( + InputChannel inputChannel, Looper looper, Choreographer choreographer) { + super(inputChannel, looper, choreographer); } @Override @@ -117,7 +122,14 @@ class TaskPositioner implements DimLayer.DimLayerUser { boolean handled = false; try { - boolean endDrag = false; + if (mDragEnded) { + // The drag has ended but the clean-up message has not been processed by + // window manager. Drop events that occur after this until window manager + // has a chance to clean-up the input handle. + handled = true; + return; + } + final float newX = motionEvent.getRawX(); final float newY = motionEvent.getRawY(); @@ -133,30 +145,32 @@ class TaskPositioner implements DimLayer.DimLayerUser { Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}"); } synchronized (mService.mWindowMap) { - endDrag = notifyMoveLocked(newX, newY); + mDragEnded = notifyMoveLocked(newX, newY); } + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.TaskPositioner.resizeTask"); try { mService.mActivityManager.resizeTask( mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER); } catch(RemoteException e) {} + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } break; case MotionEvent.ACTION_UP: { if (DEBUG_TASK_POSITIONING) { Slog.w(TAG, "ACTION_UP @ {" + newX + ", " + newY + "}"); } - endDrag = true; + mDragEnded = true; } break; case MotionEvent.ACTION_CANCEL: { if (DEBUG_TASK_POSITIONING) { Slog.w(TAG, "ACTION_CANCEL @ {" + newX + ", " + newY + "}"); } - endDrag = true; + mDragEnded = true; } break; } - if (endDrag) { + if (mDragEnded) { synchronized (mService.mWindowMap) { endDragLocked(); } @@ -214,8 +228,8 @@ class TaskPositioner implements DimLayer.DimLayerUser { mClientChannel = channels[1]; mService.mInputManager.registerInputChannel(mServerChannel, null); - mInputEventReceiver = new WindowPositionerEventReceiver(mClientChannel, - mService.mH.getLooper()); + mInputEventReceiver = new WindowPositionerEventReceiver( + mClientChannel, mService.mH.getLooper(), mService.mChoreographer); mDragApplicationHandle = new InputApplicationHandle(null); mDragApplicationHandle.name = TAG; @@ -262,6 +276,8 @@ class TaskPositioner implements DimLayer.DimLayerUser { mSideMargin = mService.dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics); mMinVisibleWidth = mService.dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics); mMinVisibleHeight = mService.dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics); + + mDragEnded = false; } void unregister() { @@ -292,6 +308,7 @@ class TaskPositioner implements DimLayer.DimLayerUser { mDimLayer = null; } mCurrentDimSide = CTRL_NONE; + mDragEnded = true; // Resume rotations after a drag. if (WindowManagerService.DEBUG_ORIENTATION) { diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 13625557e8f3..10ea4e2ba036 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.app.ActivityManager.*; import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT; +import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK; import static com.android.server.wm.WindowManagerService.TAG; import android.annotation.IntDef; @@ -86,6 +87,7 @@ public class TaskStack implements DimLayer.DimLayerUser { static final int DOCKED_TOP = 2; static final int DOCKED_RIGHT = 3; static final int DOCKED_BOTTOM = 4; + @IntDef({ DOCKED_INVALID, DOCKED_LEFT, @@ -180,12 +182,45 @@ public class TaskStack implements DimLayer.DimLayerUser { return true; } - void getBounds(Rect out) { + /** Bounds of the stack without adjusting for other factors in the system like visibility + * of docked stack. + * Most callers should be using {@link #getBounds} as it take into consideration other system + * factors. */ + void getRawBounds(Rect out) { out.set(mBounds); } + /** Return true if the current bound can get outputted to the rest of the system as-is. */ + private boolean useCurrentBounds() { + if (mFullscreen + || mStackId == DOCKED_STACK_ID + || mDisplayContent == null + || mDisplayContent.getDockedStackLocked() != null) { + return true; + } + return false; + } + + /** Bounds of the stack with other system factors taken into consideration. */ + void getBounds(Rect out) { + if (useCurrentBounds()) { + // No need to adjust the output bounds if fullscreen or the docked stack is visible + // since it is already what we want to represent to the rest of the system. + out.set(mBounds); + return; + } + + // The bounds has been adjusted to accommodate for a docked stack, but the docked stack + // is not currently visible. Go ahead a represent it as fullscreen to the rest of the + // system. + mDisplayContent.getLogicalDisplayRect(out); + } + void updateDisplayInfo(Rect bounds) { if (mDisplayContent != null) { + for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { + mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent); + } if (bounds != null) { setBounds(bounds); } else if (mFullscreen) { @@ -194,10 +229,13 @@ public class TaskStack implements DimLayer.DimLayerUser { TmpRect2.set(mBounds); mDisplayContent.rotateBounds( mRotation, mDisplayContent.getDisplayInfo().rotation, TmpRect2); - setBounds(TmpRect2); - } - for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { - mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent); + if (setBounds(TmpRect2)) { + // Post message to inform activity manager of the bounds change simulating + // a one-way call. We do this to prevent a deadlock between window manager + // lock and activity manager lock been held. + mService.mH.sendMessage( + mService.mH.obtainMessage(RESIZE_STACK, mStackId, -1, mBounds)); + } } } } @@ -352,7 +390,8 @@ public class TaskStack implements DimLayer.DimLayerUser { // the docked stack occupies a dedicated region on screen. bounds = new Rect(); displayContent.getLogicalDisplayRect(mTmpRect); - getInitialDockedStackBounds(mTmpRect, bounds, mStackId); + getInitialDockedStackBounds(mTmpRect, bounds, mStackId, + mDisplayContent.mDividerControllerLocked.getWidthAdjustment()); } updateDisplayInfo(bounds); @@ -371,27 +410,29 @@ public class TaskStack implements DimLayer.DimLayerUser { * @param displayRect The bounds of the display the docked stack is on. * @param outBounds Output bounds that should be used for the stack. * @param stackId Id of stack we are calculating the bounds for. + * @param adjustment */ - private static void getInitialDockedStackBounds( - Rect displayRect, Rect outBounds, int stackId) { + private static void getInitialDockedStackBounds(Rect displayRect, Rect outBounds, int stackId, + int adjustment) { // Docked stack start off occupying half the screen space. + final boolean dockedStack = stackId == DOCKED_STACK_ID; final boolean splitHorizontally = displayRect.width() > displayRect.height(); final boolean topOrLeftCreateMode = WindowManagerService.sDockedStackCreateMode == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; - final boolean placeTopOrLeft = (stackId == DOCKED_STACK_ID && topOrLeftCreateMode) - || (stackId != DOCKED_STACK_ID && !topOrLeftCreateMode); + final boolean placeTopOrLeft = (dockedStack && topOrLeftCreateMode) + || (!dockedStack && !topOrLeftCreateMode); outBounds.set(displayRect); if (placeTopOrLeft) { if (splitHorizontally) { - outBounds.right = displayRect.centerX(); + outBounds.right = displayRect.centerX() - adjustment; } else { - outBounds.bottom = displayRect.centerY(); + outBounds.bottom = displayRect.centerY() - adjustment; } } else { if (splitHorizontally) { - outBounds.left = displayRect.centerX(); + outBounds.left = displayRect.centerX() + adjustment; } else { - outBounds.top = displayRect.centerY(); + outBounds.top = displayRect.centerY() + adjustment; } } } @@ -404,7 +445,8 @@ public class TaskStack implements DimLayer.DimLayerUser { private void resizeNonDockedStacks(boolean fullscreen) { mDisplayContent.getLogicalDisplayRect(mTmpRect); if (!fullscreen) { - getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID); + getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID, + mDisplayContent.mDividerControllerLocked.getWidth()); } final int count = mService.mStackIdToStack.size(); @@ -434,8 +476,7 @@ public class TaskStack implements DimLayer.DimLayerUser { for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) { // We are in the middle of changing the state of displays/stacks/tasks. We need // to finish that, before we let layout interfere with it. - mService.removeWindowInnerLocked(appWindows.get(winNdx), - false /* performLayout */); + mService.removeWindowLocked(appWindows.get(winNdx)); doAnotherLayoutPass = true; } } @@ -516,9 +557,23 @@ public class TaskStack implements DimLayer.DimLayerUser { } } + /** Fullscreen status of the stack without adjusting for other factors in the system like + * visibility of docked stack. + * Most callers should be using {@link #isFullscreen} as it take into consideration other + * system factors. */ + boolean getRawFullscreen() { + return mFullscreen; + } + @Override public boolean isFullscreen() { - return mFullscreen; + if (useCurrentBounds()) { + return mFullscreen; + } + // The bounds has been adjusted to accommodate for a docked stack, but the docked stack + // is not currently visible. Go ahead a represent it as fullscreen to the rest of the + // system. + return true; } @Override @@ -546,14 +601,14 @@ public class TaskStack implements DimLayer.DimLayerUser { final int orientation = mService.mCurConfiguration.orientation; if (orientation == Configuration.ORIENTATION_PORTRAIT) { // Portrait mode, docked either at the top or the bottom. - if (mTmpRect.top - mBounds.top < mTmpRect.bottom - mBounds.bottom) { + if (mBounds.top - mTmpRect.top < mTmpRect.bottom - mBounds.bottom) { return DOCKED_TOP; } else { return DOCKED_BOTTOM; } } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { // Landscape mode, docked either on the left or on the right. - if (mTmpRect.left - mBounds.left < mTmpRect.right - mBounds.right) { + if (mBounds.left - mTmpRect.left < mTmpRect.right - mBounds.right) { return DOCKED_LEFT; } else { return DOCKED_RIGHT; @@ -562,4 +617,16 @@ public class TaskStack implements DimLayer.DimLayerUser { return DOCKED_INVALID; } } + + boolean isVisibleLocked() { + for (int i = mTasks.size() - 1; i >= 0; i--) { + Task task = mTasks.get(i); + for (int j = task.mAppTokens.size() - 1; j >= 0; j--) { + if (!task.mAppTokens.get(j).hidden) { + return true; + } + } + } + return false; + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 29598ab19476..74572cfcdee2 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -17,12 +17,14 @@ package com.android.server.wm; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; +import static android.app.ActivityManager.DOCKED_STACK_ID; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; +import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; @@ -33,6 +35,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; @@ -219,6 +222,7 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean HIDE_STACK_CRAWLS = true; static final int LAYOUT_REPEAT_THRESHOLD = 4; + static final boolean PROFILE_ORIENTATION = false; static final boolean localLOGV = DEBUG; @@ -921,6 +925,7 @@ public class WindowManagerService extends IWindowManager.Stub mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean( com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout); + LocalServices.addService(WindowManagerInternal.class, new LocalService()); initPolicy(); @@ -1854,6 +1859,11 @@ public class WindowManagerService extends IWindowManager.Stub + attrs.token + ". Aborting."); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } + } else if (type == TYPE_DOCK_DIVIDER) { + if (displayContent.mDividerControllerLocked.hasDivider()) { + Slog.w(TAG, "Attempted to add docked stack divider twice. Aborting."); + return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; + } } else if (token.appWindowToken != null) { Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type); // It is not valid to use an app token with other system types; we will @@ -1886,13 +1896,13 @@ public class WindowManagerService extends IWindowManager.Stub return res; } - if (outInputChannel != null && (attrs.inputFeatures - & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { + final boolean openInputChannels = (outInputChannel != null + && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0); + if (openInputChannels) { String name = win.makeInputChannelName(); InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); win.setInputChannel(inputChannels[0]); inputChannels[1].transferTo(outInputChannel); - mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); } @@ -2166,10 +2176,7 @@ public class WindowManagerService extends IWindowManager.Stub // The exit animation is running... wait for it! win.mExiting = true; win.mRemoveOnExit = true; - final DisplayContent displayContent = win.getDisplayContent(); - if (displayContent != null) { - displayContent.layoutNeeded = true; - } + win.setDisplayLayoutNeeded(); final boolean focusChanged = updateFocusedWindowLocked( UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/); mWindowPlacerLocked.performSurfacePlacement(); @@ -2198,7 +2205,7 @@ public class WindowManagerService extends IWindowManager.Stub removeWindowInnerLocked(win, true); } - void removeWindowInnerLocked(WindowState win, boolean performLayout) { + private void removeWindowInnerLocked(WindowState win, boolean performLayout) { if (win.mRemoved) { // Nothing to do. return; @@ -2292,10 +2299,7 @@ public class WindowManagerService extends IWindowManager.Stub windows.remove(win); if (!mWindowPlacerLocked.isInLayout()) { assignLayersLocked(windows); - final DisplayContent displayContent = win.getDisplayContent(); - if (displayContent != null) { - displayContent.layoutNeeded = true; - } + win.setDisplayLayoutNeeded(); if (performLayout) { mWindowPlacerLocked.performSurfacePlacement(); } @@ -2377,10 +2381,7 @@ public class WindowManagerService extends IWindowManager.Stub w.mGivenVisibleInsets.scale(w.mGlobalScale); w.mGivenTouchableRegion.scale(w.mGlobalScale); } - final DisplayContent displayContent = w.getDisplayContent(); - if (displayContent != null) { - displayContent.layoutNeeded = true; - } + w.setDisplayLayoutNeeded(); mWindowPlacerLocked.performSurfacePlacement(); } } @@ -2722,10 +2723,7 @@ public class WindowManagerService extends IWindowManager.Stub WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; } - final DisplayContent displayContent = win.getDisplayContent(); - if (displayContent != null) { - displayContent.layoutNeeded = true; - } + win.setDisplayLayoutNeeded(); win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; configChanged = updateOrientationFromAppTokensLocked(false); mWindowPlacerLocked.performSurfacePlacement(); @@ -2818,10 +2816,7 @@ public class WindowManagerService extends IWindowManager.Stub getDefaultDisplayContentLocked().pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; } - final DisplayContent displayContent = win.getDisplayContent(); - if (displayContent != null) { - displayContent.layoutNeeded = true; - } + win.setDisplayLayoutNeeded(); mWindowPlacerLocked.requestTraversal(); } } @@ -3260,8 +3255,7 @@ public class WindowManagerService extends IWindowManager.Stub // if we're about to tear down this window and not seek for // the behind activity, don't use it for orientation - if (!findingBehind - && (!atoken.hidden && atoken.hiddenRequested)) { + if (!findingBehind && !atoken.hidden && atoken.hiddenRequested) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken + " -- going to hide"); continue; @@ -3282,7 +3276,7 @@ public class WindowManagerService extends IWindowManager.Stub } // We ignore any hidden applications on the top. - if (atoken.hiddenRequested || atoken.willBeHidden) { + if (atoken.hiddenRequested) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken + " -- hidden on top"); continue; @@ -3778,7 +3772,6 @@ public class WindowManagerService extends IWindowManager.Stub if (!ttoken.hidden) { wtoken.hidden = false; wtoken.hiddenRequested = false; - wtoken.willBeHidden = false; } if (wtoken.clientHidden != ttoken.clientHidden) { wtoken.clientHidden = ttoken.clientHidden; @@ -3834,25 +3827,6 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override - public void setAppWillBeHidden(IBinder token) { - if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, - "setAppWillBeHidden()")) { - throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); - } - - AppWindowToken wtoken; - - synchronized(mWindowMap) { - wtoken = findAppWindowToken(token); - if (wtoken == null) { - Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token); - return; - } - wtoken.willBeHidden = true; - } - } - public void setAppFullscreen(IBinder token, boolean toOpaque) { synchronized (mWindowMap) { AppWindowToken atoken = findAppWindowToken(token); @@ -3889,7 +3863,6 @@ public class WindowManagerService extends IWindowManager.Stub wtoken.sendAppVisibilityToClients(); } - wtoken.willBeHidden = false; // Allow for state changes and animation to be applied if: // * token is transitioning visibility state // * or the token was marked as hidden and is exiting before we had a chance to play the @@ -3942,10 +3915,7 @@ public class WindowManagerService extends IWindowManager.Stub } } changed = true; - final DisplayContent displayContent = win.getDisplayContent(); - if (displayContent != null) { - displayContent.layoutNeeded = true; - } + win.setDisplayLayoutNeeded(); } } else if (win.isVisibleNow()) { if (!runningAppAnimation) { @@ -3959,10 +3929,7 @@ public class WindowManagerService extends IWindowManager.Stub } } changed = true; - final DisplayContent displayContent = win.getDisplayContent(); - if (displayContent != null) { - displayContent.layoutNeeded = true; - } + win.setDisplayLayoutNeeded(); } } @@ -4130,10 +4097,7 @@ public class WindowManagerService extends IWindowManager.Stub } w.mLastFreezeDuration = 0; unfrozeWindows = true; - final DisplayContent displayContent = w.getDisplayContent(); - if (displayContent != null) { - displayContent.layoutNeeded = true; - } + w.setDisplayLayoutNeeded(); } } if (force || unfrozeWindows) { @@ -4436,7 +4400,6 @@ public class WindowManagerService extends IWindowManager.Stub mInputMonitor.setUpdateInputWindowsNeededLw(); mWindowPlacerLocked.performSurfacePlacement(); mInputMonitor.updateInputWindowsLw(false /*force*/); - //dump(); } @@ -4521,17 +4484,16 @@ public class WindowManagerService extends IWindowManager.Stub } stack.attachDisplayContent(displayContent); displayContent.attachStack(stack, onTop); - moveStackWindowsLocked(displayContent); final WindowList windows = displayContent.getWindowList(); for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { windows.get(winNdx).reportResized(); } - if (stack.isFullscreen()) { + if (stack.getRawFullscreen()) { return null; } Rect bounds = new Rect(); - stack.getBounds(bounds); + stack.getRawBounds(bounds); return bounds; } } @@ -4649,7 +4611,7 @@ public class WindowManagerService extends IWindowManager.Stub stack.getDisplayContent().layoutNeeded = true; mWindowPlacerLocked.performSurfacePlacement(); } - return stack.isFullscreen(); + return stack.getRawFullscreen(); } } @@ -6869,37 +6831,29 @@ public class WindowManagerService extends IWindowManager.Stub } boolean startMovingTask(IWindow window, float startX, float startY) { - WindowState callingWin = null; + WindowState win = null; synchronized (mWindowMap) { - callingWin = windowForClientLocked(null, window, false); - if (!startPositioningLocked(callingWin, false /*resize*/, startX, startY)) { + win = windowForClientLocked(null, window, false); + if (!startPositioningLocked(win, false /*resize*/, startX, startY)) { return false; } } try { - mActivityManager.setFocusedTask(callingWin.getTask().mTaskId); + mActivityManager.setFocusedTask(win.getTask().mTaskId); } catch(RemoteException e) {} return true; } private void startResizingTask(DisplayContent displayContent, int startX, int startY) { - int taskId = -1; - AppWindowToken atoken = null; + WindowState win = null; synchronized (mWindowMap) { - taskId = displayContent.taskIdForControlPoint(startX, startY); - Task task = mTaskIdToTask.get(taskId); - if (task == null || task.mAppTokens == null) { - return; - } - AppTokenList tokens = task.mAppTokens; - atoken = tokens.get(tokens.size() - 1); - WindowState win = atoken.findMainWindow(); + win = displayContent.findWindowForControlPoint(startX, startY); if (!startPositioningLocked(win, true /*resize*/, startX, startY)) { return; } } try { - mActivityManager.setFocusedTask(taskId); + mActivityManager.setFocusedTask(win.getTask().mTaskId); } catch(RemoteException e) {} } @@ -7144,22 +7098,7 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayContent displayContent = getDisplayContentLocked(displayId); if (displayContent != null) { mAnimator.addDisplayLocked(displayId); - synchronized(displayContent.mDisplaySizeLock) { - // Bootstrap the default logical display from the display manager. - final DisplayInfo displayInfo = displayContent.getDisplayInfo(); - DisplayInfo newDisplayInfo = mDisplayManagerInternal.getDisplayInfo(displayId); - if (newDisplayInfo != null) { - displayInfo.copyFrom(newDisplayInfo); - } - displayContent.mInitialDisplayWidth = displayInfo.logicalWidth; - displayContent.mInitialDisplayHeight = displayInfo.logicalHeight; - displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi; - displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth; - displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight; - displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity; - displayContent.mBaseDisplayRect.set(0, 0, - displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight); - } + displayContent.initializeDisplayBaseInfo(); } } } @@ -7220,6 +7159,11 @@ public class WindowManagerService extends IWindowManager.Stub public static final int TAP_DOWN_OUTSIDE_TASK = 40; public static final int FINISH_TASK_POSITIONING = 41; + public static final int UPDATE_DOCKED_STACK_DIVIDER = 42; + + public static final int RESIZE_STACK = 43; + public static final int RESIZE_TASK = 44; + @Override public void handleMessage(Message msg) { if (DEBUG_WINDOW_TRACE) { @@ -7759,6 +7703,29 @@ public class WindowManagerService extends IWindowManager.Stub } } break; + case UPDATE_DOCKED_STACK_DIVIDER: { + DisplayContent content = (DisplayContent) msg.obj; + synchronized (mWindowMap) { + content.mDividerControllerLocked.update(); + } + } + break; + case RESIZE_TASK: { + try { + mActivityManager.resizeTask(msg.arg1, (Rect) msg.obj, msg.arg2); + } catch (RemoteException e) { + // This will not happen since we are in the same process. + } + } + break; + case RESIZE_STACK: { + try { + mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj); + } catch (RemoteException e) { + // This will not happen since we are in the same process. + } + } + break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG, "handleMessage: exit"); @@ -8300,7 +8267,7 @@ public class WindowManagerService extends IWindowManager.Stub final int numTokens = tokens.size(); for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) { final AppWindowToken wtoken = tokens.get(tokenNdx); - if (wtoken.mIsExiting) { + if (wtoken.mIsExiting && !wtoken.mReplacingWindow) { continue; } i = reAddAppWindowsLocked(displayContent, i, wtoken); @@ -8370,6 +8337,13 @@ public class WindowManagerService extends IWindowManager.Stub } else if (wtoken != null) { winAnimator.mAnimLayer = w.mLayer + wtoken.mAppAnimator.animLayerAdjustment; + if (wtoken.mReplacingWindow && wtoken.mAnimateReplacingWindow) { + // We know that we will be animating a relaunching window in the near future, + // which will receive a z-order increase. We want the replaced window to + // immediately receive the same treatment, e.g. to be above the dock divider. + w.mLayer += TYPE_LAYER_OFFSET; + winAnimator.mAnimLayer += TYPE_LAYER_OFFSET; + } } else { winAnimator.mAnimLayer = w.mLayer; } @@ -9892,6 +9866,12 @@ public class WindowManagerService extends IWindowManager.Stub return mWindowMap; } + /** + * Hint to a token that its activity will relaunch, which will trigger removal and addition of + * a window. + * @param token Application token for which the activity will be relaunched. + * @param animate Whether to animate the addition of the new window. + */ public void setReplacingWindow(IBinder token, boolean animate) { synchronized (mWindowMap) { AppWindowToken appWindowToken = findAppWindowToken(token); @@ -10081,8 +10061,6 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void saveLastInputMethodWindowForTransition() { synchronized (mWindowMap) { - // TODO(multidisplay): Pass in the displayID. - DisplayContent displayContent = getDefaultDisplayContentLocked(); if (mInputMethodWindow != null) { mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index a6478a024963..55ddbc06d959 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; @@ -23,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; @@ -33,10 +35,12 @@ import static com.android.server.wm.WindowManagerService.DEBUG_POWER; import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE; import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY; +import android.app.ActivityManager; import android.app.AppOpsManager; import android.os.PowerManager; import android.os.RemoteCallbackList; import android.os.SystemClock; +import android.os.Trace; import android.os.WorkSource; import android.util.DisplayMetrics; import android.util.TimeUtils; @@ -128,7 +132,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean mAttachedHidden; // is our parent window hidden? boolean mWallpaperVisible; // for wallpaper, what was last vis report? boolean mDragResizing; - boolean mDragResizeChanging; RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks; @@ -707,6 +710,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { mContentFrame.set(mFrame); mVisibleFrame.set(mContentFrame); mStableFrame.set(mContentFrame); + } else if (mAttrs.type == TYPE_DOCK_DIVIDER) { + mDisplayContent.mDividerControllerLocked.positionDockedStackedDivider(mFrame); } else { mContentFrame.set(Math.max(mContentFrame.left, mFrame.left), Math.max(mContentFrame.top, mFrame.top), @@ -940,7 +945,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ void getVisibleBounds(Rect bounds, boolean forTouch) { boolean intersectWithStackBounds = mAppToken != null && mAppToken.mCropWindowsToStack; - boolean isFreeform = false; bounds.setEmpty(); mTmpRect.setEmpty(); if (intersectWithStackBounds) { @@ -952,13 +956,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } - final Task task = getTask(); - if (task != null) { - task.getBounds(bounds); - isFreeform = task.inFreeformWorkspace(); - if (intersectWithStackBounds) { - bounds.intersect(mTmpRect); - } + bounds.set(mVisibleFrame); + if (intersectWithStackBounds) { + bounds.intersect(mTmpRect); } if (bounds.isEmpty()) { @@ -968,7 +968,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } return; } - if (forTouch && isFreeform) { + if (forTouch && inFreeformWorkspace()) { final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics(); final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics); bounds.inset(-delta, -delta); @@ -1323,6 +1323,12 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } + void setDisplayLayoutNeeded() { + if (mDisplayContent != null) { + mDisplayContent.layoutNeeded = true; + } + } + private class DeathRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { @@ -1467,10 +1473,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { // We want the tag name to be somewhat stable so that it is easier to correlate // in wake lock statistics. So in particular, we don't want to include the // window's hash code as in toString(). - CharSequence tag = mAttrs.getTitle(); - if (tag == null) { - tag = mAttrs.packageName; - } + final CharSequence tag = getWindowTag(); mDrawLock = mService.mPowerManager.newWakeLock( PowerManager.DRAW_WAKE_LOCK, "Window:" + tag); mDrawLock.setReferenceCounted(false); @@ -1607,6 +1610,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } void reportResized() { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag()); try { if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this + ": " + mCompatFrame); @@ -1672,6 +1676,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mService.mPendingRemove.add(this); mService.mWindowPlacerLocked.requestTraversal(); } + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } public void registerFocusObserver(IWindowFocusObserver observer) { @@ -1703,13 +1708,23 @@ final class WindowState implements WindowManagerPolicy.WindowState { } boolean isDragResizeChanged() { + return mDragResizing != computeDragResizing(); + } + + private boolean computeDragResizing() { final Task task = getTask(); - return task != null && mDragResizing != task.isDragResizing(); + if (task == null) { + return false; + } + if (task.isDragResizing()) { + return true; + } + return mDisplayContent.mDividerControllerLocked.isResizing() && + !task.inFreeformWorkspace() && !task.isFullscreen(); } void setDragResizing() { - final Task task = getTask(); - mDragResizing = task != null && task.isDragResizing(); + mDragResizing = computeDragResizing(); } boolean isDragResizing() { @@ -1903,15 +1918,20 @@ final class WindowState implements WindowManagerPolicy.WindowState { String makeInputChannelName() { return Integer.toHexString(System.identityHashCode(this)) - + " " + mAttrs.getTitle(); + + " " + getWindowTag(); + } + + private CharSequence getWindowTag() { + CharSequence tag = mAttrs.getTitle(); + if (tag == null || tag.length() <= 0) { + tag = mAttrs.packageName; + } + return tag; } @Override public String toString() { - CharSequence title = mAttrs.getTitle(); - if (title == null || title.length() <= 0) { - title = mAttrs.packageName; - } + final CharSequence title = getWindowTag(); if (mStringNameCache == null || mLastTitle != title || mWasExiting != mExiting) { mLastTitle = title; mWasExiting = mExiting; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 07e1fce4c741..60bf57154bc6 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static com.android.server.wm.WindowManagerService.DEBUG_ANIM; import static com.android.server.wm.WindowManagerService.DEBUG_LAYERS; @@ -868,14 +869,18 @@ class WindowStateAnimator { mSurfaceW = width; mSurfaceH = height; - final boolean isHwAccelerated = (attrs.flags & - WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; + final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0; final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format; if (!PixelFormat.formatHasAlpha(attrs.format) + // Don't make surface with surfaceInsets opaque as they display a + // translucent shadow. && attrs.surfaceInsets.left == 0 && attrs.surfaceInsets.top == 0 && attrs.surfaceInsets.right == 0 - && attrs.surfaceInsets.bottom == 0) { + && attrs.surfaceInsets.bottom == 0 + // Don't make surface opaque when resizing to reduce the amount of + // artifacts shown in areas the app isn't drawing content to. + && !w.isDragResizing()) { flags |= SurfaceControl.OPAQUE; } @@ -1087,6 +1092,8 @@ class WindowStateAnimator { mAnimator.getScreenRotationAnimationLocked(displayId); final boolean screenAnimation = screenRotationAnimation != null && screenRotationAnimation.isAnimating(); + + mHasClipRect = false; if (selfTransformation || attachedTransformation != null || appTransformation != null || screenAnimation) { // cache often used attributes locally @@ -1165,7 +1172,6 @@ class WindowStateAnimator { // transforming since it is more important to have that // animation be smooth. mShownAlpha = mAlpha; - mHasClipRect = false; if (!mService.mLimitedAlphaCompositing || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format) || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy) @@ -1368,7 +1374,12 @@ class WindowStateAnimator { // so we need to translate to match the actual surface coordinates. clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top); - adjustCropToStackBounds(w, clipRect); + // We don't want to clip to stack bounds windows that are currently doing entrance + // animation. This is necessary for docking operation, otherwise the window will be + // suddenly cut off. + if (!mAnimator.mAnimating) { + adjustCropToStackBounds(w, clipRect); + } if (!clipRect.equals(mLastClipRect)) { mLastClipRect.set(clipRect); @@ -1394,7 +1405,11 @@ class WindowStateAnimator { private void adjustCropToStackBounds(WindowState w, Rect clipRect) { final AppWindowToken appToken = w.mAppToken; - if (appToken != null && appToken.mCropWindowsToStack) { + // We don't apply the the stack bounds to the window that is being replaced, because it was + // living in a different stack. If we suddenly crop it to the new stack bounds, it might + // get cut off. We don't want it to happen, so we let it ignore the stack bounds until it + // gets removed. The window that will replace it will abide them. + if (appToken != null && appToken.mCropWindowsToStack && !appToken.mReplacingWindow) { TaskStack stack = w.getTask().mStack; stack.getBounds(mTmpStackBounds); final int surfaceX = (int) mSurfaceX; @@ -1707,8 +1722,7 @@ class WindowStateAnimator { return false; } final LayoutParams attrs = mWin.getAttrs(); - final boolean isHwAccelerated = (attrs.flags & - WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0; + final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0; final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format; if (format == mSurfaceFormat) { setOpaqueLocked(!PixelFormat.formatHasAlpha(attrs.format)); diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index e77ebe76b291..df0a1c9d43d5 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -47,6 +47,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.provider.Settings; +import android.util.ArraySet; import android.util.Slog; import android.view.Display; import android.view.DisplayInfo; @@ -966,6 +967,7 @@ class WindowSurfacePlacer { } mService.mPolicy.finishLayoutLw(); + mService.mH.obtainMessage(UPDATE_DOCKED_STACK_DIVIDER, displayContent).sendToTarget(); } /** @@ -1228,11 +1230,15 @@ class WindowSurfacePlacer { final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating() ? null : wallpaperTarget; + final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps; + final ArraySet<AppWindowToken> closingApps = mService.mClosingApps; if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New wallpaper target=" + wallpaperTarget + ", oldWallpaper=" + oldWallpaper + ", lower target=" + lowerWallpaperTarget - + ", upper target=" + upperWallpaperTarget); + + ", upper target=" + upperWallpaperTarget + + ", openingApps=" + openingApps + + ", closingApps=" + closingApps); mService.mAnimateWallpaperWithTarget = false; if (closingAppHasWallpaper && openingAppHasWallpaper) { if (DEBUG_APP_TRANSITIONS) @@ -1251,15 +1257,16 @@ class WindowSurfacePlacer { } if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit: " + AppTransition.appTransitionToString(transit)); - } else if ((oldWallpaper != null) && !mService.mOpeningApps.isEmpty() - && !mService.mOpeningApps.contains(oldWallpaper.mAppToken)) { - // We are transitioning from an activity with - // a wallpaper to one without. + } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty() + && !openingApps.contains(oldWallpaper.mAppToken) + && closingApps.contains(oldWallpaper.mAppToken)) { + // We are transitioning from an activity with a wallpaper to one without. transit = AppTransition.TRANSIT_WALLPAPER_CLOSE; if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: " + AppTransition.appTransitionToString(transit)); - } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) { + } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() && + openingApps.contains(wallpaperTarget.mAppToken)) { // We are transitioning from an activity without // a wallpaper to now showing the wallpaper transit = AppTransition.TRANSIT_WALLPAPER_OPEN; diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp index 3fd0f84f5957..5cbb277a2f12 100644 --- a/services/core/jni/com_android_server_AlarmManagerService.cpp +++ b/services/core/jni/com_android_server_AlarmManagerService.cpp @@ -460,7 +460,7 @@ static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jl return result; } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"init", "()J", (void*)android_server_AlarmManagerService_init}, {"close", "(J)V", (void*)android_server_AlarmManagerService_close}, diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp index 8f4fb51093d9..ed79ceb3a9d3 100644 --- a/services/core/jni/com_android_server_AssetAtlasService.cpp +++ b/services/core/jni/com_android_server_AssetAtlasService.cpp @@ -204,7 +204,7 @@ static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject const char* const kClassPathName = "com/android/server/AssetAtlasService"; -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nUploadAtlas", "(Landroid/view/GraphicBuffer;Landroid/graphics/Bitmap;)Z", (void*) com_android_server_AssetAtlasService_upload }, }; diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp index f5121cdf5580..7104870349b5 100644 --- a/services/core/jni/com_android_server_ConsumerIrService.cpp +++ b/services/core/jni/com_android_server_ConsumerIrService.cpp @@ -100,7 +100,7 @@ static jintArray halGetCarrierFrequencies(JNIEnv *env, jobject /* obj */, return freqsOut.getJavaArray(); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "halOpen", "()J", (void *)halOpen }, { "halTransmit", "(JI[I)I", (void *)halTransmit }, { "halGetCarrierFrequencies", "(J)[I", (void *)halGetCarrierFrequencies}, diff --git a/services/core/jni/com_android_server_PersistentDataBlockService.cpp b/services/core/jni/com_android_server_PersistentDataBlockService.cpp index 4ccfa56cd30c..06de592d7533 100644 --- a/services/core/jni/com_android_server_PersistentDataBlockService.cpp +++ b/services/core/jni/com_android_server_PersistentDataBlockService.cpp @@ -97,7 +97,7 @@ namespace android { return wipe_block_device(fd); } - static JNINativeMethod sMethods[] = { + static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"nativeGetBlockDeviceSize", "(Ljava/lang/String;)J", (void*)com_android_server_PersistentDataBlockService_getBlockDeviceSize}, {"nativeWipe", "(Ljava/lang/String;)I", (void*)com_android_server_PersistentDataBlockService_wipe}, diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp index d48d159b1178..1bd7a599ed60 100644 --- a/services/core/jni/com_android_server_SerialService.cpp +++ b/services/core/jni/com_android_server_SerialService.cpp @@ -55,7 +55,7 @@ static jobject android_server_SerialService_open(JNIEnv *env, jobject /* thiz */ } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "native_open", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", (void*)android_server_SerialService_open }, }; diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp index 64514a9f72e8..c7d6b95083d2 100644 --- a/services/core/jni/com_android_server_SystemServer.cpp +++ b/services/core/jni/com_android_server_SystemServer.cpp @@ -37,7 +37,7 @@ static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jo /* * JNI registration. */ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService }, }; diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp index a1bff9d850bf..3733a55e7504 100644 --- a/services/core/jni/com_android_server_UsbDeviceManager.cpp +++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp @@ -118,7 +118,7 @@ static jint android_server_UsbDeviceManager_getAudioMode(JNIEnv* /* env */, jobj return result; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "nativeGetAccessoryStrings", "()[Ljava/lang/String;", (void*)android_server_UsbDeviceManager_getAccessoryStrings }, { "nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;", diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp index d8c172fd51cc..795f6aa6018a 100644 --- a/services/core/jni/com_android_server_UsbHostManager.cpp +++ b/services/core/jni/com_android_server_UsbHostManager.cpp @@ -186,7 +186,7 @@ static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus }, { "nativeOpenDevice", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", (void*)android_server_UsbHostManager_openDevice }, diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index fb1166b41d41..64278ed4499b 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -46,7 +46,7 @@ static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */) vibrator_off(); } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "vibratorExists", "()Z", (void*)vibratorExists }, { "vibratorOn", "(J)V", (void*)vibratorOn }, { "vibratorOff", "()V", (void*)vibratorOff } diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp index dfc5ef6ec366..5c4365979644 100644 --- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp +++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp @@ -170,7 +170,7 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf) return mergedreasonpos - mergedreason; } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup }, }; diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp index 7faeb49d7b56..2d0dfd2f7f26 100644 --- a/services/core/jni/com_android_server_connectivity_Vpn.cpp +++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp @@ -350,7 +350,7 @@ static bool delAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddres //------------------------------------------------------------------------------ -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"jniCreate", "(I)I", (void *)create}, {"jniGetName", "(I)Ljava/lang/String;", (void *)getName}, {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses}, diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp index f2d0f060c66c..b72cf4dc94d0 100644 --- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp +++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp @@ -384,7 +384,7 @@ static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ; } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J", diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp index 11388d80a9d2..bdc109d086f6 100644 --- a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp +++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp @@ -120,7 +120,7 @@ static void android_server_InputApplicationHandle_nativeDispose(JNIEnv* env, job } -static JNINativeMethod gInputApplicationHandleMethods[] = { +static const JNINativeMethod gInputApplicationHandleMethods[] = { /* name, signature, funcPtr */ { "nativeDispose", "()V", (void*) android_server_InputApplicationHandle_nativeDispose }, diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index e29d0a94610c..1d4f047ff605 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -1369,7 +1369,7 @@ static void nativeMonitor(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) { // ---------------------------------------------------------------------------- -static JNINativeMethod gInputManagerMethods[] = { +static const JNINativeMethod gInputManagerMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J", diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp index 01c51cf6cfe0..92ef7f1ae096 100644 --- a/services/core/jni/com_android_server_input_InputWindowHandle.cpp +++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp @@ -210,7 +210,7 @@ static void android_server_InputWindowHandle_nativeDispose(JNIEnv* env, jobject } -static JNINativeMethod gInputWindowHandleMethods[] = { +static const JNINativeMethod gInputWindowHandleMethods[] = { /* name, signature, funcPtr */ { "nativeDispose", "()V", (void*) android_server_InputWindowHandle_nativeDispose }, diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp index b2b27835274d..3f074f52f443 100644 --- a/services/core/jni/com_android_server_lights_LightsService.cpp +++ b/services/core/jni/com_android_server_lights_LightsService.cpp @@ -126,7 +126,7 @@ static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr, } } -static JNINativeMethod method_table[] = { +static const JNINativeMethod method_table[] = { { "init_native", "()J", (void*)init_native }, { "finalize_native", "(J)V", (void*)finalize_native }, { "setLight_native", "(JIIIIII)V", (void*)setLight_native }, diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp index c0a0c9cddba5..774577d43d69 100644 --- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp +++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp @@ -1023,7 +1023,7 @@ static void RemoveGeofences( env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/); } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { //{"name", "signature", functionPointer } {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)}, {"nativeInit", "()V", reinterpret_cast<void*>(Init)}, diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp index 5c27b1f65f17..b8d4196dad16 100644 --- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp @@ -1434,7 +1434,7 @@ static void android_location_GpsLocationProvider_configuration_update(JNIEnv* en env->ReleaseStringUTFChars(config_content, data); } -static JNINativeMethod sMethods[] = { +static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported}, diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 1662755511f4..2fdb8e2469cd 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -166,7 +166,7 @@ static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint dat // ---------------------------------------------------------------------------- -static JNINativeMethod gPowerManagerServiceMethods[] = { +static const JNINativeMethod gPowerManagerServiceMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "()V", (void*) nativeInit }, diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp index 507bc9cb5269..89b2a47d73c6 100644 --- a/services/core/jni/com_android_server_tv_TvInputHal.cpp +++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp @@ -662,7 +662,7 @@ static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) { delete tvInputHal; } -static JNINativeMethod gTvInputHalMethods[] = { +static const JNINativeMethod gTvInputHalMethods[] = { /* name, signature, funcPtr */ { "nativeOpen", "(Landroid/os/MessageQueue;)J", (void*) nativeOpen }, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index b0a04c71db48..2dd7cdea7305 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -29,6 +29,7 @@ import static org.xmlpull.v1.XmlPullParser.TEXT; import android.Manifest.permission; import android.accessibilityservice.AccessibilityServiceInfo; import android.accounts.AccountManager; +import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityManagerNative; import android.app.AlarmManager; @@ -54,6 +55,7 @@ import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; @@ -76,7 +78,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.PersistableBundle; import android.os.PowerManager; -import android.os.PowerManager.WakeLock; import android.os.PowerManagerInternal; import android.os.Process; import android.os.RecoverySystem; @@ -269,17 +270,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; final Context mContext; - final PackageManager mPackageManager; + final Injector mInjector; + final IPackageManager mIPackageManager; final UserManager mUserManager; - final PowerManager.WakeLock mWakeLock; final LocalService mLocalService; - final PowerManagerInternal mPowerManagerInternal; - - final IWindowManager mIWindowManager; - final NotificationManager mNotificationManager; - // Stores and loads state on device and profile owners. private final Owners mOwners; @@ -995,7 +991,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean removed = false; if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle); DevicePolicyData policy = getUserData(userHandle); - IPackageManager pm = AppGlobals.getPackageManager(); synchronized (this) { for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { ActiveAdmin aa = policy.mAdminList.get(i); @@ -1004,9 +999,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // then check if the package and receiver still exist. final String adminPackage = aa.info.getPackageName(); if (packageName == null || packageName.equals(adminPackage)) { - if (pm.getPackageInfo(adminPackage, 0, userHandle) == null - || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) - == null) { + if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null + || mIPackageManager.getReceiverInfo( + aa.info.getComponent(), 0, userHandle) == null) { removed = true; policy.mAdminList.remove(i); policy.mAdminMap.remove(aa.info.getComponent()); @@ -1027,7 +1022,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { || packageName.equals(policy.mDelegatedCertInstallerPackage))) { try { // Check if delegated cert installer package is removed. - if (pm.getPackageInfo( + if (mIPackageManager.getPackageInfo( policy.mDelegatedCertInstallerPackage, 0, userHandle) == null) { policy.mDelegatedCertInstallerPackage = null; saveSettingsLocked(policy.mUserHandle); @@ -1039,120 +1034,146 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - /** Unit test will override it to inject a mock. */ + /** + * Unit test will subclass it to inject mocks. + */ @VisibleForTesting - Owners newOwners() { - return new Owners(mContext); - } + static class Injector { - /** Unit test will override it to inject a mock. */ - @VisibleForTesting - UserManager getUserManager() { - return UserManager.get(mContext); - } + private final Context mContext; - /** Unit test will override it to inject a mock. */ - @VisibleForTesting - PackageManager getPackageManager() { - return mContext.getPackageManager(); - } + Injector(Context context) { + mContext = context; + } - /** Unit test will override it to inject a mock. */ - @VisibleForTesting - NotificationManager getNotificationManager() { - return mContext.getSystemService(NotificationManager.class); - } + Owners newOwners() { + return new Owners(mContext); + } - /** Unit test will override it to inject a mock. */ - @VisibleForTesting - PowerManagerInternal getPowerManagerInternal() { - return LocalServices.getService(PowerManagerInternal.class); - } + UserManager getUserManager() { + return UserManager.get(mContext); + } - /** Unit test will override it to inject a mock. */ - @VisibleForTesting - IWindowManager newIWindowManager() { - return IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)); - } + NotificationManager getNotificationManager() { + return mContext.getSystemService(NotificationManager.class); + } - /** Unit test will override it to inject a mock. */ - @VisibleForTesting - IActivityManager getIActivityManager() { - return ActivityManagerNative.getDefault(); - } + PowerManagerInternal getPowerManagerInternal() { + return LocalServices.getService(PowerManagerInternal.class); + } - /** Unit test will override it to inject a mock. */ - @VisibleForTesting - LockPatternUtils newLockPatternUtils(Context context) { - return new LockPatternUtils(context); - } + IWindowManager getIWindowManager() { + return IWindowManager.Stub + .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)); + } - /** Unit test will override it to inject. */ - @VisibleForTesting - Looper getMyLooper() { - return Looper.myLooper(); - } + IActivityManager getIActivityManager() { + return ActivityManagerNative.getDefault(); + } - @VisibleForTesting - long binderClearCallingIdentity() { - return Binder.clearCallingIdentity(); - } + IPackageManager getIPackageManager() { + return AppGlobals.getPackageManager(); + } - @VisibleForTesting - void binderRestoreCallingIdentity(long token) { - Binder.restoreCallingIdentity(token); - } + IBackupManager getIBackupManager() { + return IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + } - @VisibleForTesting - int binderGetCallingUid() { - return Binder.getCallingUid(); - } + IAudioService getIAudioService() { + return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE)); + } - @VisibleForTesting - int binderGetCallingPid() { - return Binder.getCallingPid(); - } + LockPatternUtils newLockPatternUtils() { + return new LockPatternUtils(mContext); + } - @VisibleForTesting - UserHandle binderGetCallingUserHandle() { - return Binder.getCallingUserHandle(); - } + Looper getMyLooper() { + return Looper.myLooper(); + } - @VisibleForTesting - boolean binderIsCallingUidMyUid() { - return getCallingUid() == Process.myUid(); - } + long binderClearCallingIdentity() { + return Binder.clearCallingIdentity(); + } - @VisibleForTesting - File environmentGetUserSystemDirectory(int userId) { - return Environment.getUserSystemDirectory(userId); - } + void binderRestoreCallingIdentity(long token) { + Binder.restoreCallingIdentity(token); + } - @VisibleForTesting - WakeLock powerManagerNewWakeLock(int levelAndFlags, String tag) { - return mContext.getSystemService(PowerManager.class).newWakeLock(levelAndFlags, tag); - } + int binderGetCallingUid() { + return Binder.getCallingUid(); + } - @VisibleForTesting - void powerManagerGoToSleep(long time, int reason, int flags) { - mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags); + int binderGetCallingPid() { + return Binder.getCallingPid(); + } + + UserHandle binderGetCallingUserHandle() { + return Binder.getCallingUserHandle(); + } + + boolean binderIsCallingUidMyUid() { + return getCallingUid() == Process.myUid(); + } + + File environmentGetUserSystemDirectory(int userId) { + return Environment.getUserSystemDirectory(userId); + } + + void powerManagerGoToSleep(long time, int reason, int flags) { + mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags); + } + + boolean systemPropertiesGetBoolean(String key, boolean def) { + return SystemProperties.getBoolean(key, def); + } + + long systemPropertiesGetLong(String key, long def) { + return SystemProperties.getLong(key, def); + } + + String systemPropertiesGet(String key, String def) { + return SystemProperties.get(key, def); + } + + String systemPropertiesGet(String key) { + return SystemProperties.get(key); + } + + void systemPropertiesSet(String key, String value) { + SystemProperties.set(key, value); + } + + boolean userManagerIsSplitSystemUser() { + return UserManager.isSplitSystemUser(); + } + + String getDevicePolicyFilePathForSystemUser() { + return "/data/system/"; + } } /** * Instantiates the service. */ public DevicePolicyManagerService(Context context) { - mContext = context; - mHandler = new Handler(getMyLooper()); - mOwners = newOwners(); - mUserManager = getUserManager(); - mPackageManager = getPackageManager(); - mHasFeature = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN); - mPowerManagerInternal = getPowerManagerInternal(); - mWakeLock = powerManagerNewWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM"); - mIWindowManager = newIWindowManager(); - mNotificationManager = getNotificationManager(); + this(new Injector(context)); + } + + @VisibleForTesting + DevicePolicyManagerService(Injector injector) { + mInjector = injector; + mContext = Preconditions.checkNotNull(injector.mContext); + mHandler = new Handler(Preconditions.checkNotNull(injector.getMyLooper())); + mOwners = Preconditions.checkNotNull(injector.newOwners()); + + mUserManager = Preconditions.checkNotNull(injector.getUserManager()); + mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager()); + mLocalService = new LocalService(); + + mHasFeature = mContext.getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN); if (!mHasFeature) { // Skip the rest of the initialization return; @@ -1164,35 +1185,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { filter.addAction(Intent.ACTION_USER_STARTED); filter.addAction(KeyChain.ACTION_STORAGE_CHANGED); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); + mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addDataScheme("package"); - context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); + mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); filter = new IntentFilter(); filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); - context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); + mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); LocalServices.addService(DevicePolicyManagerInternal.class, mLocalService); } /** - * We need it for testing to allow accessing context from the test-only subclass while this - * class's constructor is still running. - */ - @VisibleForTesting - Context getContext() { - return mContext; - } - - /** * Creates and loads the policy data from xml. * @param userHandle the user for whom to load the policy data * @return */ + @NonNull DevicePolicyData getUserData(int userHandle) { synchronized (this) { DevicePolicyData policy = mUserData.get(userHandle); @@ -1216,11 +1229,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * @return */ DevicePolicyData getUserDataUnchecked(int userHandle) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { return getUserData(userHandle); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } @@ -1237,7 +1250,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (policy != null) { mUserData.remove(userHandle); } - File policyFile = new File(environmentGetUserSystemDirectory(userHandle), + File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle), DEVICE_POLICIES_XML); policyFile.delete(); Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath()); @@ -1277,7 +1290,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { alarmTime = now + alarmInterval; } - long token = binderClearCallingIdentity(); + long token = mInjector.binderClearCallingIdentity(); try { AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD, @@ -1289,7 +1302,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { am.set(AlarmManager.RTC, alarmTime, pi); } } finally { - binderRestoreCallingIdentity(token); + mInjector.binderRestoreCallingIdentity(token); } } @@ -1305,7 +1318,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) throws SecurityException { - final int callingUid = binderGetCallingUid(); + final int callingUid = mInjector.binderGetCallingUid(); ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid); if (result != null) { @@ -1329,7 +1342,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + admin.info.getTagForPolicy(reqPolicy)); } else { throw new SecurityException("No active admin owned by uid " - + binderGetCallingUid() + " for policy #" + reqPolicy); + + mInjector.binderGetCallingUid() + " for policy #" + reqPolicy); } } @@ -1345,7 +1358,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (admin.getUid() != uid) { throw new SecurityException("Admin " + who + " is not owned by uid " - + binderGetCallingUid()); + + mInjector.binderGetCallingUid()); } if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) { return admin; @@ -1509,17 +1522,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private JournaledFile makeJournaledFile(int userHandle) { final String base = userHandle == UserHandle.USER_SYSTEM - ? getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML - : new File(environmentGetUserSystemDirectory(userHandle), DEVICE_POLICIES_XML) - .getAbsolutePath(); + ? mInjector.getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML + : new File(mInjector.environmentGetUserSystemDirectory(userHandle), + DEVICE_POLICIES_XML).getAbsolutePath(); return new JournaledFile(new File(base), new File(base + ".tmp")); } - @VisibleForTesting - String getDevicePolicyFilePathForSystemUser() { - return "/data/system/"; - } - private void saveSettingsLocked(int userHandle) { DevicePolicyData policy = getUserData(userHandle); JournaledFile journal = makeJournaledFile(userHandle); @@ -1630,11 +1638,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void sendChangedNotification(int userHandle) { Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle)); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } @@ -1766,9 +1774,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // sufficiently what is currently set. Note that this is only // a sanity check in case the two get out of sync; this should // never normally happen. - final long identity = binderClearCallingIdentity(); + final long identity = mInjector.binderClearCallingIdentity(); try { - LockPatternUtils utils = newLockPatternUtils(mContext); + LockPatternUtils utils = mInjector.newLockPatternUtils(); if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) { Slog.w(LOG_TAG, "Active password quality 0x" + Integer.toHexString(policy.mActivePasswordQuality) @@ -1784,7 +1792,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mActivePasswordNonLetter = 0; } } finally { - binderRestoreCallingIdentity(identity); + mInjector.binderRestoreCallingIdentity(identity); } validatePasswordOwnerLocked(policy); @@ -1798,26 +1806,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void updateLockTaskPackagesLocked(List<String> packages, int userId) { - IActivityManager am = getIActivityManager(); - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { - am.updateLockTaskPackages(userId, packages.toArray(new String[packages.size()])); + mInjector.getIActivityManager() + .updateLockTaskPackages(userId, packages.toArray(new String[packages.size()])); } catch (RemoteException e) { // Not gonna happen. } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } private void updateDeviceOwnerLocked() { - IActivityManager am = getIActivityManager(); - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { - am.updateDeviceOwner(getDeviceOwner()); + mInjector.getIActivityManager() + .updateDeviceOwner(getDeviceOwner()); } catch (RemoteException e) { // Not gonna happen. } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } @@ -1862,17 +1870,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Ensure the status of the camera is synced down to the system. Interested native services // should monitor this value and act accordingly. String cameraPropertyForUser = SYSTEM_PROP_DISABLE_CAMERA_PREFIX + policy.mUserHandle; - boolean systemState = SystemProperties.getBoolean(cameraPropertyForUser, false); + boolean systemState = mInjector.systemPropertiesGetBoolean(cameraPropertyForUser, false); boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle); if (cameraDisabled != systemState) { - long token = binderClearCallingIdentity(); + long token = mInjector.binderClearCallingIdentity(); try { String value = cameraDisabled ? "1" : "0"; if (DBG) Slog.v(LOG_TAG, "Change in camera state [" + cameraPropertyForUser + "] = " + value); - SystemProperties.set(cameraPropertyForUser, value); + mInjector.systemPropertiesSet(cameraPropertyForUser, value); } finally { - binderRestoreCallingIdentity(token); + mInjector.binderRestoreCallingIdentity(token); } } } @@ -1912,14 +1920,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void ensureDeviceOwnerUserStarted() { if (mOwners.hasDeviceOwner()) { - final IActivityManager am = getIActivityManager(); final int userId = mOwners.getDeviceOwnerUserId(); if (VERBOSE_LOG) { Log.v(LOG_TAG, "Starting non-system DO user: " + userId); } if (userId != UserHandle.USER_SYSTEM) { try { - am.startUserInBackground(userId); + mInjector.getIActivityManager().startUserInBackground(userId); // STOPSHIP Prevent the DO user from being killed. @@ -2020,7 +2027,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.e(LOG_TAG, "Could not connect to KeyChain service", e); } if (!hasCert) { - mNotificationManager.cancelAsUser( + mInjector.getNotificationManager().cancelAsUser( null, MONITORING_CERT_NOTIFICATION_ID, userHandle); return; } @@ -2065,7 +2072,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { com.android.internal.R.color.system_notification_accent_color)) .build(); - mNotificationManager.notifyAsUser( + mInjector.getNotificationManager().notifyAsUser( null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle); } } @@ -2094,7 +2101,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new IllegalArgumentException("Bad admin: " + adminReceiver); } synchronized (this) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) { @@ -2121,7 +2128,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED, onEnableData, null); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -2215,7 +2222,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (admin == null) { return; } - if (admin.getUid() != binderGetCallingUid()) { + if (admin.getUid() != mInjector.binderGetCallingUid()) { // Active device owners must remain active admins. if (isDeviceOwner(adminReceiver.getPackageName())) { return; @@ -2223,11 +2230,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_DEVICE_ADMINS, null); } - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { removeActiveAdminLocked(adminReceiver, userHandle); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -2497,7 +2504,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { || activeAdmin.crossProfileWidgetProviders.isEmpty()) { return null; } - if (binderIsCallingUidMyUid()) { + if (mInjector.binderIsCallingUidMyUid()) { return new ArrayList<>(activeAdmin.crossProfileWidgetProviders); } else { return activeAdmin.crossProfileWidgetProviders; @@ -3062,7 +3069,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - int callingUid = binderGetCallingUid(); + int callingUid = mInjector.binderGetCallingUid(); DevicePolicyData policy = getUserData(userHandle); if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) { Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user"); @@ -3078,7 +3085,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Don't do this with the lock held, because it is going to call // back in to the service. - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { LockPatternUtils utils = new LockPatternUtils(mContext); if (!TextUtils.isEmpty(password)) { @@ -3099,7 +3106,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } return true; @@ -3149,7 +3156,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { if (timeMs <= 0) { timeMs = Integer.MAX_VALUE; @@ -3161,9 +3168,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } policy.mLastMaximumTimeToLock = timeMs; - mPowerManagerInternal.setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs); + // TODO It can overflow. Cap it. + mInjector.getPowerManagerInternal() + .setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } @@ -3215,26 +3224,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void lockNowUnchecked() { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { // Power off the display - powerManagerGoToSleep(SystemClock.uptimeMillis(), + mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0); // Ensure the device is locked new LockPatternUtils(mContext).requireStrongAuth( STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL); - mIWindowManager.lockNow(null); + mInjector.getIWindowManager().lockNow(null); } catch (RemoteException e) { } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } - private boolean isExtStorageEncrypted() { - String state = SystemProperties.get("vold.decrypt"); - return !"".equals(state); - } - @Override public void enforceCanManageCaCerts(ComponentName who) { if (who == null) { @@ -3249,7 +3253,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean isCallerDelegatedCertInstaller() { - final int callingUid = binderGetCallingUid(); + final int callingUid = mInjector.binderGetCallingUid(); final int userHandle = UserHandle.getUserId(callingUid); synchronized (this) { final DevicePolicyData policy = getUserData(userHandle); @@ -3284,7 +3288,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); - final long id = binderClearCallingIdentity(); + final long id = mInjector.binderClearCallingIdentity(); try { final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); try { @@ -3299,7 +3303,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1); Thread.currentThread().interrupt(); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } return false; } @@ -3315,7 +3319,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceCanManageCaCerts(admin); final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); - final long id = binderClearCallingIdentity(); + final long id = mInjector.binderClearCallingIdentity(); try { final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); try { @@ -3331,7 +3335,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.w(LOG_TAG, "CaCertUninstaller: ", ie); Thread.currentThread().interrupt(); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } @@ -3347,7 +3351,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); - final long id = binderClearCallingIdentity(); + final long id = mInjector.binderClearCallingIdentity(); try { final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); try { @@ -3362,7 +3366,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.w(LOG_TAG, "Interrupted while installing certificate", e); Thread.currentThread().interrupt(); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } return false; } @@ -3371,11 +3375,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias, final IBinder response) { // Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers. - if (UserHandle.getAppId(binderGetCallingUid()) != Process.SYSTEM_UID) { + if (UserHandle.getAppId(mInjector.binderGetCallingUid()) != Process.SYSTEM_UID) { return; } - final UserHandle caller = binderGetCallingUserHandle(); + final UserHandle caller = mInjector.binderGetCallingUserHandle(); // If there is a profile owner, redirect to that; otherwise query the device owner. ComponentName aliasChooser = getProfileOwner(caller.getIdentifier()); if (aliasChooser == null && caller.isOwner()) { @@ -3396,7 +3400,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS, alias); intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE, response); - final long id = binderClearCallingIdentity(); + final long id = mInjector.binderClearCallingIdentity(); try { mContext.sendOrderedBroadcastAsUser(intent, caller, null, new BroadcastReceiver() { @Override @@ -3406,7 +3410,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } }, null, Activity.RESULT_OK, null, null); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } @@ -3477,7 +3481,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final String source = admin.info.getComponent().flattenToShortString(); - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) { boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName()) @@ -3498,7 +3502,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { wipeDeviceOrUserLocked(wipeExtRequested, userHandle, "DevicePolicyManager.wipeData() from " + source); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -3511,7 +3515,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void run() { try { - IActivityManager am = getIActivityManager(); + IActivityManager am = mInjector.getIActivityManager(); if (am.getCurrentUser().id == userHandle) { am.switchUser(UserHandle.USER_SYSTEM); } @@ -3539,11 +3543,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { .setColor(mContext.getColor(R.color.system_notification_accent_color)) .setStyle(new Notification.BigTextStyle().bigText(contentText)) .build(); - mNotificationManager.notify(PROFILE_WIPED_NOTIFICATION_ID, notification); + mInjector.getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification); } private void clearWipeProfileNotification() { - mNotificationManager.cancel(PROFILE_WIPED_NOTIFICATION_ID); + mInjector.getNotificationManager().cancel(PROFILE_WIPED_NOTIFICATION_ID); } @Override @@ -3603,7 +3607,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { || p.mActivePasswordNumeric != numbers || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { p.mActivePasswordQuality = quality; p.mActivePasswordLength = length; @@ -3621,7 +3625,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -3657,7 +3661,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { boolean wipeData = false; int identifier = 0; @@ -3688,7 +3692,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "reportFailedPasswordAttempt()"); } } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } @@ -3701,7 +3705,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { DevicePolicyData policy = getUserData(userHandle); if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { policy.mFailedPasswordAttempts = 0; policy.mPasswordOwner = -1; @@ -3712,7 +3716,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -3763,11 +3767,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Reset the global proxy accordingly // Do this using system permissions, as apps cannot write to secure settings - long origId = binderClearCallingIdentity(); + long origId = mInjector.binderClearCallingIdentity(); try { resetGlobalProxyLocked(policy); } finally { - binderRestoreCallingIdentity(origId); + mInjector.binderRestoreCallingIdentity(origId); } return null; } @@ -3802,13 +3806,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); } - long token = binderClearCallingIdentity(); + long token = mInjector.binderClearCallingIdentity(); try { ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); connectivityManager.setGlobalProxy(proxyInfo); } finally { - binderRestoreCallingIdentity(token); + mInjector.binderRestoreCallingIdentity(token); } } @@ -3969,15 +3973,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}. */ private int getEncryptionStatus() { - String status = SystemProperties.get("ro.crypto.state", "unsupported"); + String status = mInjector.systemPropertiesGet("ro.crypto.state", "unsupported"); if ("encrypted".equalsIgnoreCase(status)) { - final long token = binderClearCallingIdentity(); + final long token = mInjector.binderClearCallingIdentity(); try { return LockPatternUtils.isDeviceEncrypted() ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE : DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY; } finally { - binderRestoreCallingIdentity(token); + mInjector.binderRestoreCallingIdentity(token); } } else if ("unencrypted".equalsIgnoreCase(status)) { return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE; @@ -4042,13 +4046,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void updateScreenCaptureDisabledInWindowManager(int userHandle, boolean disabled) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { - mIWindowManager.setScreenCaptureDisabled(userHandle, disabled); + mInjector.getIWindowManager().setScreenCaptureDisabled(userHandle, disabled); } catch (RemoteException e) { Log.w(LOG_TAG, "Unable to notify WindowManager.", e); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } @@ -4073,12 +4077,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Turn AUTO_TIME on in settings if it is required if (required) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AUTO_TIME, 1 /* AUTO_TIME on */); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -4187,7 +4191,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return 0; } enforceCrossUserPermission(userHandle); - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { synchronized (this) { if (who != null) { @@ -4230,7 +4234,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return which; } } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } @@ -4240,7 +4244,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } if (packageName == null - || !Owners.isInstalledForUser(packageName, userId)) { + || !isPackageInstalledForUser(packageName, userId)) { throw new IllegalArgumentException("Invalid package name " + packageName + " for device owner"); } @@ -4248,15 +4252,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceCanSetDeviceOwner(userId); // Shutting down backup manager service permanently. - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { - IBackupManager ibm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, false); + mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, false); } catch (RemoteException e) { throw new IllegalStateException("Failed deactivating backup service.", e); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } mOwners.setDeviceOwner(packageName, ownerName, userId); @@ -4264,12 +4266,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { updateDeviceOwnerLocked(); Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED); - ident = binderClearCallingIdentity(); + ident = mInjector.binderClearCallingIdentity(); try { // TODO Send to system too? mContext.sendBroadcastAsUser(intent, new UserHandle(userId)); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } return true; } @@ -4301,11 +4303,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return null; } + // TODO: Do we really need it? getDeviceOwner() doesn't require it. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); synchronized (this) { if (!mOwners.hasDeviceOwner()) { return null; } + // TODO This totally ignores the name passed to setDeviceOwner (change for b/20679292) + // Should setDeviceOwner/ProfileOwner still take a name? String deviceOwnerPackage = mOwners.getDeviceOwnerPackageName(); return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_SYSTEM); } @@ -4334,7 +4339,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkNotNull(packageName, "packageName is null"); try { int uid = mContext.getPackageManager().getPackageUid(packageName, 0); - if (uid != binderGetCallingUid()) { + if (uid != mInjector.binderGetCallingUid()) { throw new SecurityException("Invalid packageName"); } } catch (NameNotFoundException e) { @@ -4350,15 +4355,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mOwners.writeDeviceOwner(); updateDeviceOwnerLocked(); // Reactivate backup service. - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { - IBackupManager ibm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, true); + mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, true); } catch (RemoteException e) { throw new IllegalStateException("Failed reactivating backup service.", e); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -4370,15 +4373,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (initializer == null || !mOwners.hasDeviceOwner() || - !Owners.isInstalledForUser(initializer.getPackageName(), + !isPackageInstalledForUser(initializer.getPackageName(), mOwners.getDeviceOwnerUserId())) { throw new IllegalArgumentException("Invalid component name " + initializer + " for device initializer or no device owner set"); } boolean isInitializerSystemApp; try { - isInitializerSystemApp = isSystemApp(AppGlobals.getPackageManager(), - initializer.getPackageName(), binderGetCallingUserHandle().getIdentifier()); + isInitializerSystemApp = isSystemApp(mIPackageManager, + initializer.getPackageName(), + mInjector.binderGetCallingUserHandle().getIdentifier()); } catch (RemoteException | IllegalArgumentException e) { isInitializerSystemApp = false; Slog.e(LOG_TAG, "Fail to check if device initialzer is system app.", e); @@ -4461,9 +4465,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId()); - if (admin.getUid() != binderGetCallingUid()) { + if (admin.getUid() != mInjector.binderGetCallingUid()) { throw new SecurityException("Admin " + who + " is not owned by uid " - + binderGetCallingUid()); + + mInjector.binderGetCallingUid()); } if (!isDeviceInitializer(admin.info.getPackageName()) @@ -4472,12 +4476,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "clearDeviceInitializer can only be called by the device initializer/owner"); } synchronized (this) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { mOwners.clearDeviceInitializer(); mOwners.writeDeviceOwner(); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -4488,7 +4492,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } if (who == null - || !Owners.isInstalledForUser(who.getPackageName(), userHandle)) { + || !isPackageInstalledForUser(who.getPackageName(), userHandle)) { throw new IllegalArgumentException("Component " + who + " not installed for userId:" + userHandle); } @@ -4505,7 +4509,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return; } - UserHandle callingUser = binderGetCallingUserHandle(); + UserHandle callingUser = mInjector.binderGetCallingUserHandle(); // Check if this is the profile owner who is calling getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); synchronized (this) { @@ -4525,15 +4529,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mStatusBarDisabled = false; saveSettingsLocked(userId); - final long ident = binderClearCallingIdentity(); + final long ident = mInjector.binderClearCallingIdentity(); try { clearUserRestrictions(userHandle); - AppGlobals.getPackageManager().updatePermissionFlagsForAllApps( + mIPackageManager.updatePermissionFlagsForAllApps( PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0 /* flagValues */, userHandle.getIdentifier()); } catch (RemoteException re) { } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } @@ -4541,11 +4545,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void clearUserRestrictions(UserHandle userHandle) { Bundle userRestrictions = mUserManager.getUserRestrictions(); mUserManager.setUserRestrictions(new Bundle(), userHandle); - IAudioService iAudioService = IAudioService.Stub.asInterface( - ServiceManager.getService(Context.AUDIO_SERVICE)); if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) { try { - iAudioService.setMasterMute(true, 0, mContext.getPackageName(), + mInjector.getIAudioService().setMasterMute(true, 0, mContext.getPackageName(), userHandle.getIdentifier()); } catch (RemoteException e) { // Not much we can do here. @@ -4553,7 +4555,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) { try { - iAudioService.setMicrophoneMute(true, mContext.getPackageName(), + mInjector.getIAudioService().setMicrophoneMute(true, mContext.getPackageName(), userHandle.getIdentifier()); } catch (RemoteException e) { // Not much we can do here. @@ -4570,9 +4572,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return true; } - DevicePolicyData policy = getUserData(userHandle); - // If policy is null, return true, else check if the setup has completed. - return policy == null || policy.mUserSetupComplete; + return getUserData(userHandle).mUserSetupComplete; } @Override @@ -4593,11 +4593,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "This method can only be called by device initializers"); } - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { if (!isDeviceOwner(activeAdmin.info.getPackageName())) { - IPackageManager ipm = AppGlobals.getPackageManager(); - ipm.setComponentEnabledSetting(who, + mIPackageManager.setComponentEnabledSetting(who, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP, userId); @@ -4614,7 +4613,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.i(LOG_TAG, "Can't talk to package manager", e); return false; } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } return true; } @@ -4632,7 +4631,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { mUserManager.setUserEnabled(userId); UserInfo parent = mUserManager.getProfileParent(userId); @@ -4642,7 +4641,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcastAsUser(intent, new UserHandle(parent.id)); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -4654,11 +4653,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Check if this is the profile owner (includes device owner). getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { mUserManager.setUserName(userId, profileName); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } @@ -4708,7 +4707,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Canonical name for a given package. */ private String getApplicationLabel(String packageName, int userHandle) { - long token = binderClearCallingIdentity(); + long token = mInjector.binderClearCallingIdentity(); try { final Context userContext; try { @@ -4726,7 +4725,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return result != null ? result.toString() : null; } finally { - binderRestoreCallingIdentity(token); + mInjector.binderRestoreCallingIdentity(token); } } @@ -4752,7 +4751,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new IllegalStateException("Trying to set the profile owner, but profile owner " + "is already set."); } - int callingUid = binderGetCallingUid(); + int callingUid = mInjector.binderGetCallingUid(); if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { if (hasUserSetupCompleted(userHandle) && AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) { @@ -4785,13 +4784,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new IllegalStateException("User not running: " + userId); } - int callingUid = binderGetCallingUid(); + int callingUid = mInjector.binderGetCallingUid(); if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { if (!hasUserSetupCompleted(UserHandle.USER_SYSTEM)) { return; } // STOPSHIP Do proper check in split user mode - if (!UserManager.isSplitSystemUser()) { + if (!mInjector.userManagerIsSplitSystemUser()) { if (mUserManager.getUserCount() > 1) { throw new IllegalStateException( "Not allowed to set the device owner because there " @@ -4810,7 +4809,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null); // STOPSHIP Do proper check in split user mode - if (!UserManager.isSplitSystemUser()) { + if (!mInjector.userManagerIsSplitSystemUser()) { if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) { throw new IllegalStateException("Cannot set the device owner if the device is " + "already set-up"); @@ -4822,7 +4821,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (userHandle < 0) { throw new IllegalArgumentException("Invalid userId " + userHandle); } - final int callingUid = binderGetCallingUid(); + final int callingUid = mInjector.binderGetCallingUid(); if (userHandle == UserHandle.getUserId(callingUid)) return; if (callingUid != Process.SYSTEM_UID && callingUid != 0) { mContext.enforceCallingOrSelfPermission( @@ -4838,32 +4837,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private UserInfo getProfileParent(int userHandle) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { return mUserManager.getProfileParent(userHandle); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } private boolean isManagedProfile(int userHandle) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { return mUserManager.getUserInfo(userHandle).isManagedProfile(); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } private void enableIfNecessary(String packageName, int userId) { try { - IPackageManager ipm = AppGlobals.getPackageManager(); - ApplicationInfo ai = ipm.getApplicationInfo(packageName, + ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName, PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId); if (ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { - ipm.setApplicationEnabledSetting(packageName, + mIPackageManager.setApplicationEnabledSetting(packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager"); } @@ -4877,8 +4875,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid=" - + binderGetCallingPid() - + ", uid=" + binderGetCallingUid()); + + mInjector.binderGetCallingPid() + + ", uid=" + mInjector.binderGetCallingUid()); return; } @@ -4919,14 +4917,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { - pm.addPersistentPreferredActivity(filter, activity, userHandle); + mIPackageManager.addPersistentPreferredActivity(filter, activity, userHandle); } catch (RemoteException re) { // Shouldn't happen } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -4938,14 +4935,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { - pm.clearPackagePersistentPreferredActivities(packageName, userHandle); + mIPackageManager.clearPackagePersistentPreferredActivities(packageName, userHandle); } catch (RemoteException re) { // Shouldn't happen } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -4957,11 +4953,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { mUserManager.setApplicationRestrictions(packageName, settings, userHandle); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5059,7 +5055,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public ComponentName getRestrictionsProvider(int userHandle) { synchronized (this) { - if (binderGetCallingUid() != Process.SYSTEM_UID) { + if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("Only the system can query the permission provider"); } DevicePolicyData userData = getUserData(userHandle); @@ -5074,8 +5070,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { UserInfo parent = mUserManager.getProfileParent(callingUserId); if (parent == null) { @@ -5084,17 +5079,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } if ((flags & DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED) != 0) { - pm.addCrossProfileIntentFilter(filter, who.getPackageName(), callingUserId, - parent.id, 0); + mIPackageManager.addCrossProfileIntentFilter( + filter, who.getPackageName(), callingUserId, parent.id, 0); } if ((flags & DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT) != 0) { - pm.addCrossProfileIntentFilter(filter, who.getPackageName(), + mIPackageManager.addCrossProfileIntentFilter(filter, who.getPackageName(), parent.id, callingUserId, 0); } } catch (RemoteException re) { // Shouldn't happen } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5105,8 +5100,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int callingUserId = UserHandle.getCallingUserId(); synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - IPackageManager pm = AppGlobals.getPackageManager(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { UserInfo parent = mUserManager.getProfileParent(callingUserId); if (parent == null) { @@ -5115,15 +5109,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } // Removing those that go from the managed profile to the parent. - pm.clearCrossProfileIntentFilters(callingUserId, who.getPackageName()); + mIPackageManager.clearCrossProfileIntentFilters( + callingUserId, who.getPackageName()); // And those that go from the parent to the managed profile. // If we want to support multiple managed profiles, we will have to only remove // those that have callingUserId as their target. - pm.clearCrossProfileIntentFilters(parent.id, who.getPackageName()); + mIPackageManager.clearCrossProfileIntentFilters(parent.id, who.getPackageName()); } catch (RemoteException re) { // Shouldn't happen } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5135,7 +5130,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean checkPackagesInPermittedListOrSystem(List<String> enabledPackages, List<String> permittedList) { int userIdToCheck = UserHandle.getCallingUserId(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { // If we have an enabled packages list for a managed profile the packages // we should check are installed for the parent user. @@ -5144,12 +5139,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { userIdToCheck = user.profileGroupId; } - IPackageManager pm = AppGlobals.getPackageManager(); for (String enabledPackage : enabledPackages) { boolean systemService = false; try { - ApplicationInfo applicationInfo = pm.getApplicationInfo(enabledPackage, - PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck); + ApplicationInfo applicationInfo = mIPackageManager.getApplicationInfo( + enabledPackage, PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck); systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } catch (RemoteException e) { Log.i(LOG_TAG, "Can't talk to package managed", e); @@ -5159,7 +5153,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } return true; } @@ -5184,7 +5178,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (packageList != null) { int userId = UserHandle.getCallingUserId(); List<AccessibilityServiceInfo> enabledServices = null; - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { UserInfo user = mUserManager.getUserInfo(userId); if (user.isManagedProfile()) { @@ -5194,7 +5188,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enabledServices = accessibilityManager.getEnabledAccessibilityServiceList( AccessibilityServiceInfo.FEEDBACK_ALL_MASK); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } if (enabledServices != null) { @@ -5265,7 +5259,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // If we have a permitted list add all system accessibility services. if (result != null) { - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { UserInfo user = mUserManager.getUserInfo(userId); if (user.isManagedProfile()) { @@ -5276,7 +5270,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { List<AccessibilityServiceInfo> installedServices = accessibilityManager.getInstalledAccessibilityServiceList(); - IPackageManager pm = AppGlobals.getPackageManager(); if (installedServices != null) { for (AccessibilityServiceInfo service : installedServices) { ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo; @@ -5287,7 +5280,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } @@ -5297,12 +5290,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean checkCallerIsCurrentUserOrProfile() { int callingUserId = UserHandle.getCallingUserId(); - long token = binderClearCallingIdentity(); + long token = mInjector.binderClearCallingIdentity(); try { UserInfo currentUser; UserInfo callingUser = mUserManager.getUserInfo(callingUserId); try { - currentUser = getIActivityManager().getCurrentUser(); + currentUser = mInjector.getIActivityManager().getCurrentUser(); } catch (RemoteException e) { Slog.e(LOG_TAG, "Failed to talk to activity managed.", e); return false; @@ -5319,7 +5312,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } } finally { - binderRestoreCallingIdentity(token); + mInjector.binderRestoreCallingIdentity(token); } return true; } @@ -5385,7 +5378,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public List getPermittedInputMethodsForCurrentUser() { UserInfo currentUser; try { - currentUser = getIActivityManager().getCurrentUser(); + currentUser = mInjector.getIActivityManager().getCurrentUser(); } catch (RemoteException e) { Slog.e(LOG_TAG, "Failed to make remote calls to get current user", e); // Activity managed is dead, just allow all IMEs @@ -5423,9 +5416,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { InputMethodManager inputMethodManager = (InputMethodManager) mContext .getSystemService(Context.INPUT_METHOD_SERVICE); List<InputMethodInfo> imes = inputMethodManager.getInputMethodList(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); if (imes != null) { for (InputMethodInfo ime : imes) { ServiceInfo serviceInfo = ime.getServiceInfo(); @@ -5436,7 +5428,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } return result; @@ -5449,7 +5441,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { UserInfo userInfo = mUserManager.createUser(name, 0 /* flags */); if (userInfo != null) { @@ -5457,7 +5449,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return null; } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5469,21 +5461,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (user == null) { return null; } - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { String profileOwnerPkg = profileOwnerComponent.getPackageName(); - final IPackageManager ipm = AppGlobals.getPackageManager(); - IActivityManager activityManager = getIActivityManager(); final int userHandle = user.getIdentifier(); try { // Install the profile owner if not present. - if (!ipm.isPackageAvailable(profileOwnerPkg, userHandle)) { - ipm.installExistingPackageAsUser(profileOwnerPkg, userHandle); + if (!mIPackageManager.isPackageAvailable(profileOwnerPkg, userHandle)) { + mIPackageManager.installExistingPackageAsUser(profileOwnerPkg, userHandle); } // Start user in background. - activityManager.startUserInBackground(userHandle); + mInjector.getIActivityManager().startUserInBackground(userHandle); } catch (RemoteException e) { Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e); } @@ -5492,7 +5482,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { setProfileOwner(profileOwnerComponent, ownerName, userHandle); return user; } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } @@ -5502,11 +5492,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { return mUserManager.removeUser(userHandle.getIdentifier()); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5517,18 +5507,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { int userId = UserHandle.USER_SYSTEM; if (userHandle != null) { userId = userHandle.getIdentifier(); } - return getIActivityManager().switchUser(userId); + return mInjector.getIActivityManager().switchUser(userId); } catch (RemoteException e) { Log.e(LOG_TAG, "Couldn't switch user", e); return false; } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5541,14 +5531,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle); // if no restrictions were saved, mUserManager.getApplicationRestrictions // returns null, but DPM method should return an empty Bundle as per JavaDoc return bundle != null ? bundle : Bundle.EMPTY; } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5571,22 +5561,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user); - IAudioService iAudioService = null; - if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key) - || UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { - iAudioService = IAudioService.Stub.asInterface( - ServiceManager.getService(Context.AUDIO_SERVICE)); - } - - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { if (enabled && !alreadyRestricted) { if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { - iAudioService.setMicrophoneMute(true, mContext.getPackageName(), - userHandle); + mInjector.getIAudioService() + .setMicrophoneMute(true, mContext.getPackageName(), userHandle); } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { - iAudioService.setMasterMute(true, 0, mContext.getPackageName(), - userHandle); + mInjector.getIAudioService() + .setMasterMute(true, 0, mContext.getPackageName(), userHandle); } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) { Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, @@ -5624,8 +5607,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Send out notifications however as some clients may want to reread the // value which actually changed due to a restriction having been applied. final String property = Settings.Secure.SYS_PROP_SETTING_VERSION; - long version = SystemProperties.getLong(property, 0) + 1; - SystemProperties.set(property, Long.toString(version)); + long version = mInjector.systemPropertiesGetLong(property, 0) + 1; + mInjector.systemPropertiesSet(property, Long.toString(version)); final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED; Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); @@ -5634,17 +5617,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (!enabled && alreadyRestricted) { if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { - iAudioService.setMicrophoneMute(false, mContext.getPackageName(), - userHandle); + mInjector.getIAudioService() + .setMicrophoneMute(false, mContext.getPackageName(), userHandle); } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { - iAudioService.setMasterMute(false, 0, mContext.getPackageName(), - userHandle); + mInjector.getIAudioService() + .setMasterMute(false, 0, mContext.getPackageName(), userHandle); } } } catch (RemoteException re) { Slog.e(LOG_TAG, "Failed to talk to AudioService.", re); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } sendChangedNotification(userHandle); } @@ -5658,15 +5641,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); - return pm.setApplicationHiddenSettingAsUser(packageName, hidden, callingUserId); + return mIPackageManager.setApplicationHiddenSettingAsUser( + packageName, hidden, callingUserId); } catch (RemoteException re) { // shouldn't happen Slog.e(LOG_TAG, "Failed to setApplicationHiddenSetting", re); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } return false; } @@ -5679,15 +5662,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); - return pm.getApplicationHiddenSettingAsUser(packageName, callingUserId); + return mIPackageManager.getApplicationHiddenSettingAsUser( + packageName, callingUserId); } catch (RemoteException re) { // shouldn't happen Slog.e(LOG_TAG, "Failed to getApplicationHiddenSettingAsUser", re); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } return false; } @@ -5702,7 +5685,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { if (DBG) { @@ -5718,19 +5701,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { primaryUser = um.getUserInfo(userId); } - IPackageManager pm = AppGlobals.getPackageManager(); - if (!isSystemApp(pm, packageName, primaryUser.id)) { + if (!isSystemApp(mIPackageManager, packageName, primaryUser.id)) { throw new IllegalArgumentException("Only system apps can be enabled this way."); } // Install the app. - pm.installExistingPackageAsUser(packageName, userId); + mIPackageManager.installExistingPackageAsUser(packageName, userId); } catch (RemoteException re) { // shouldn't happen Slog.wtf(LOG_TAG, "Failed to install " + packageName, re); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5744,7 +5726,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { UserManager um = UserManager.get(mContext); @@ -5755,8 +5737,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { primaryUser = um.getUserInfo(userId); } - IPackageManager pm = AppGlobals.getPackageManager(); - List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent, + List<ResolveInfo> activitiesToEnable = mIPackageManager.queryIntentActivities( + intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), 0, // no flags primaryUser.id); @@ -5767,9 +5749,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { for (ResolveInfo info : activitiesToEnable) { if (info.activityInfo != null) { String packageName = info.activityInfo.packageName; - if (isSystemApp(pm, packageName, primaryUser.id)) { + if (isSystemApp(mIPackageManager, packageName, primaryUser.id)) { numberOfAppsInstalled++; - pm.installExistingPackageAsUser(packageName, userId); + mIPackageManager.installExistingPackageAsUser(packageName, userId); } else { Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a" + " system app"); @@ -5783,7 +5765,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent); return 0; } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5849,15 +5831,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); - pm.setBlockUninstallForUser(packageName, uninstallBlocked, userId); + mIPackageManager.setBlockUninstallForUser(packageName, uninstallBlocked, userId); } catch (RemoteException re) { // Shouldn't happen. Slog.e(LOG_TAG, "Failed to setBlockUninstallForUser", re); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -5874,15 +5855,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); } - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { - IPackageManager pm = AppGlobals.getPackageManager(); - return pm.getBlockUninstallForUser(packageName, userId); + return mIPackageManager.getBlockUninstallForUser(packageName, userId); } catch (RemoteException re) { // Shouldn't happen. Slog.e(LOG_TAG, "Failed to getBlockUninstallForUser", re); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } return false; @@ -5934,7 +5914,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { actualLookupKey, actualContactId, originalIntent); final int callingUserId = UserHandle.getCallingUserId(); - final long ident = binderClearCallingIdentity(); + final long ident = mInjector.binderClearCallingIdentity(); try { synchronized (this) { final int managedUserId = getManagedUserId(callingUserId); @@ -5952,7 +5932,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext, intent, new UserHandle(managedUserId)); } } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } @@ -6033,7 +6013,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - int userHandle = binderGetCallingUserHandle().getIdentifier(); + int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier(); setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages))); } } @@ -6055,7 +6035,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); - int userHandle = binderGetCallingUserHandle().getIdentifier(); + int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier(); final List<String> packages = getLockTaskPackagesLocked(userHandle); return packages.toArray(new String[packages.size()]); } @@ -6074,7 +6054,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isLockTaskPermitted(String pkg) { // Get current user's devicepolicy - int uid = binderGetCallingUid(); + int uid = mInjector.binderGetCallingUid(); int userHandle = UserHandle.getUserId(uid); DevicePolicyData policy = getUserData(userHandle); synchronized (this) { @@ -6093,7 +6073,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) { - if (binderGetCallingUid() != Process.SYSTEM_UID) { + if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) { throw new SecurityException("notifyLockTaskModeChanged can only be called by system"); } synchronized (this) { @@ -6144,11 +6124,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { Settings.Global.putString(contentResolver, setting, value); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -6173,11 +6153,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "Permission denial: Profile owners cannot update %1$s", setting)); } - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { Settings.Secure.putStringForUser(contentResolver, setting, value, callingUserId); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -6188,7 +6168,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long identity = binderClearCallingIdentity(); + long identity = mInjector.binderClearCallingIdentity(); try { IAudioService iAudioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); @@ -6196,7 +6176,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (RemoteException re) { Slog.e(LOG_TAG, "Failed to setMasterMute", re); } finally { - binderRestoreCallingIdentity(identity); + mInjector.binderRestoreCallingIdentity(identity); } } } @@ -6220,11 +6200,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); - long id = binderClearCallingIdentity(); + long id = mInjector.binderClearCallingIdentity(); try { mUserManager.setUserIcon(userId, icon); } finally { - binderRestoreCallingIdentity(id); + mInjector.binderRestoreCallingIdentity(id); } } } @@ -6238,7 +6218,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final int userId = UserHandle.getCallingUserId(); LockPatternUtils utils = new LockPatternUtils(mContext); - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { // disallow disabling the keyguard if a password is currently set if (disabled && utils.isSecure(userId)) { @@ -6246,7 +6226,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } utils.setLockScreenDisabled(disabled, userId); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } return true; } @@ -6269,7 +6249,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean setStatusBarDisabledInternal(boolean disabled, int userId) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( ServiceManager.checkService(Context.STATUS_BAR_SERVICE)); @@ -6283,7 +6263,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (RemoteException e) { Slog.e(LOG_TAG, "Failed to disable the status bar", e); } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } return false; } @@ -6514,7 +6494,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Log.e(LOG_TAG, "Cannot find device owner package", e); } if (receivers != null) { - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { for (int i = 0; i < receivers.length; i++) { if (permission.BIND_DEVICE_ADMIN.equals(receivers[i].permission)) { @@ -6524,7 +6504,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -6555,12 +6535,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean setPermissionGrantState(ComponentName admin, String packageName, String permission, int grantState) throws RemoteException { - UserHandle user = binderGetCallingUserHandle(); + UserHandle user = mInjector.binderGetCallingUserHandle(); synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { - final ApplicationInfo ai = AppGlobals.getPackageManager() + final ApplicationInfo ai = mIPackageManager .getApplicationInfo(packageName, 0, user.getIdentifier()); final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion; if (targetSdkVersion < android.os.Build.VERSION_CODES.M) { @@ -6592,7 +6572,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } catch (SecurityException se) { return false; } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } @@ -6602,12 +6582,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { String permission) throws RemoteException { PackageManager packageManager = mContext.getPackageManager(); - UserHandle user = binderGetCallingUserHandle(); + UserHandle user = mInjector.binderGetCallingUserHandle(); synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - long ident = binderClearCallingIdentity(); + long ident = mInjector.binderClearCallingIdentity(); try { - int granted = AppGlobals.getPackageManager().checkPermission(permission, + int granted = mIPackageManager.checkPermission(permission, packageName, user.getIdentifier()); int permFlags = packageManager.getPermissionFlags(permission, packageName, user); if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) @@ -6621,8 +6601,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { : DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED; } } finally { - binderRestoreCallingIdentity(ident); + mInjector.binderRestoreCallingIdentity(ident); } } } + + boolean isPackageInstalledForUser(String packageName, int userHandle) { + try { + PackageInfo pi = mIPackageManager.getPackageInfo(packageName, 0, userHandle); + return (pi != null) && (pi.applicationInfo.flags != 0); + } catch (RemoteException re) { + throw new RuntimeException("Package manager has died", re); + } + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java index 87cf28f861d8..370cf48b4655 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java @@ -101,7 +101,7 @@ class Owners { public Owners(Context context) { mContext = context; - mUserManager = UserManager.get(mContext); + mUserManager = context.getSystemService(UserManager.class); } /** @@ -230,20 +230,6 @@ class Owners { return mDeviceOwner != null; } - static boolean isInstalledForUser(String packageName, int userHandle) { - try { - PackageInfo pi = (AppGlobals.getPackageManager()) - .getPackageInfo(packageName, 0, userHandle); - if (pi != null && pi.applicationInfo.flags != 0) { - return true; - } - } catch (RemoteException re) { - throw new RuntimeException("Package manager has died", re); - } - - return false; - } - private boolean readLegacyOwnerFile(File file) { if (!file.exists()) { // Already migrated or the device has no owners. diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 93dc6cbcfe99..1ec1a46f3620 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -867,6 +867,11 @@ public final class SystemServer { if (!disableNonCoreServices) { mSystemServiceManager.startService(DockObserver.class); + + if (context.getPackageManager().hasSystemFeature + (PackageManager.FEATURE_WATCH)) { + mSystemServiceManager.startService(ThermalObserver.class); + } } traceBeginAndSlog("StartWiredAccessoryManager"); diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java index 9ee9cf4fbcc6..e0d2ac12be21 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/services/net/java/android/net/dhcp/DhcpClient.java @@ -244,8 +244,9 @@ public class DhcpClient extends BaseDhcpStateMachine { private PendingIntent createStateMachineCommandIntent(final String cmdName, final int cmd) { String action = DhcpClient.class.getName() + "." + mIfaceName + "." + cmdName; - Intent intent = new Intent(action, null) - .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + Intent intent = new Intent(action, null).addFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | + Intent.FLAG_RECEIVER_FOREGROUND); // TODO: The intent's package covers the whole of the system server, so it's pretty generic. // Consider adding some sort of token as well. intent.setPackage(mContext.getPackageName()); diff --git a/core/java/android/net/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java index 2283004c7759..982bae0ccb42 100644 --- a/core/java/android/net/IpReachabilityMonitor.java +++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net; +package android.net.ip; import com.android.internal.annotations.GuardedBy; @@ -60,6 +60,74 @@ import java.util.Set; * Monitors on-link IP reachability and notifies callers whenever any on-link * addresses of interest appear to have become unresponsive. * + * This code does not concern itself with "why" a neighbour might have become + * unreachable. Instead, it primarily reacts to the kernel's notion of IP + * reachability for each of the neighbours we know to be critically important + * to normal network connectivity. As such, it is often "just the messenger": + * the neighbours about which it warns are already deemed by the kernel to have + * become unreachable. + * + * + * How it works: + * + * 1. The "on-link neighbours of interest" found in a given LinkProperties + * instance are added to a "watch list" via #updateLinkProperties(). + * This usually means all default gateways and any on-link DNS servers. + * + * 2. We listen continuously for netlink neighbour messages (RTM_NEWNEIGH, + * RTM_DELNEIGH), watching only for neighbours in the watch list. + * + * - A neighbour going into NUD_REACHABLE, NUD_STALE, NUD_DELAY, and + * even NUD_PROBE is perfectly normal; we merely record the new state. + * + * - A neighbour's entry may be deleted (RTM_DELNEIGH), for example due + * to garbage collection. This is not necessarily of immediate + * concern; we record the neighbour as moving to NUD_NONE. + * + * - A neighbour transitioning to NUD_FAILED (for any reason) is + * critically important and is handled as described below in #4. + * + * 3. All on-link neighbours in the watch list can be forcibly "probed" by + * calling #probeAll(). This should be called whenever it is important to + * verify that critical neighbours on the link are still reachable, e.g. + * when roaming between BSSIDs. + * + * - The kernel will send unicast ARP requests for IPv4 neighbours and + * unicast NS packets for IPv6 neighbours. The expected replies will + * likely be unicast. + * + * - The forced probing is done holding a wakelock. The kernel may, + * however, initiate probing of a neighbor on its own, i.e. whenever + * a neighbour has expired from NUD_DELAY. + * + * - The kernel sends: + * + * /proc/sys/net/ipv{4,6}/neigh/<ifname>/ucast_solicit + * + * number of probes (usually 3) every: + * + * /proc/sys/net/ipv{4,6}/neigh/<ifname>/retrans_time_ms + * + * number of milliseconds (usually 1000ms). This normally results in + * 3 unicast packets, 1 per second. + * + * - If no response is received to any of the probe packets, the kernel + * marks the neighbour as being in state NUD_FAILED, and the listening + * process in #2 will learn of it. + * + * 4. We call the supplied Callback#notifyLost() function if the loss of a + * neighbour in NUD_FAILED would cause IPv4 or IPv6 configuration to + * become incomplete (a loss of provisioning). + * + * - For example, losing all our IPv4 on-link DNS servers (or losing + * our only IPv6 default gateway) constitutes a loss of IPv4 (IPv6) + * provisioning; Callback#notifyLost() would be called. + * + * - Since it can be non-trivial to reacquire certain IP provisioning + * state it may be best for the link to disconnect completely and + * reconnect afresh. + * + * * @hide */ public class IpReachabilityMonitor { diff --git a/core/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java index e331701efbce..e331701efbce 100644 --- a/core/java/android/net/netlink/NetlinkConstants.java +++ b/services/net/java/android/net/netlink/NetlinkConstants.java diff --git a/core/java/android/net/netlink/NetlinkErrorMessage.java b/services/net/java/android/net/netlink/NetlinkErrorMessage.java index e2755740453a..e2755740453a 100644 --- a/core/java/android/net/netlink/NetlinkErrorMessage.java +++ b/services/net/java/android/net/netlink/NetlinkErrorMessage.java diff --git a/core/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java index 3bf75cabea17..3bf75cabea17 100644 --- a/core/java/android/net/netlink/NetlinkMessage.java +++ b/services/net/java/android/net/netlink/NetlinkMessage.java diff --git a/core/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java index 657d48c15250..657d48c15250 100644 --- a/core/java/android/net/netlink/NetlinkSocket.java +++ b/services/net/java/android/net/netlink/NetlinkSocket.java diff --git a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java index 02df1313c43f..02df1313c43f 100644 --- a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java +++ b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java diff --git a/core/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java index b68ec0bc6226..b68ec0bc6226 100644 --- a/core/java/android/net/netlink/StructNdMsg.java +++ b/services/net/java/android/net/netlink/StructNdMsg.java diff --git a/core/java/android/net/netlink/StructNdaCacheInfo.java b/services/net/java/android/net/netlink/StructNdaCacheInfo.java index 16cf56385eb8..16cf56385eb8 100644 --- a/core/java/android/net/netlink/StructNdaCacheInfo.java +++ b/services/net/java/android/net/netlink/StructNdaCacheInfo.java diff --git a/core/java/android/net/netlink/StructNlAttr.java b/services/net/java/android/net/netlink/StructNlAttr.java index 597a6aa1c9eb..597a6aa1c9eb 100644 --- a/core/java/android/net/netlink/StructNlAttr.java +++ b/services/net/java/android/net/netlink/StructNlAttr.java diff --git a/core/java/android/net/netlink/StructNlMsgErr.java b/services/net/java/android/net/netlink/StructNlMsgErr.java index f095af43c743..f095af43c743 100644 --- a/core/java/android/net/netlink/StructNlMsgErr.java +++ b/services/net/java/android/net/netlink/StructNlMsgErr.java diff --git a/core/java/android/net/netlink/StructNlMsgHdr.java b/services/net/java/android/net/netlink/StructNlMsgHdr.java index 98ab5e719d69..98ab5e719d69 100644 --- a/core/java/android/net/netlink/StructNlMsgHdr.java +++ b/services/net/java/android/net/netlink/StructNlMsgHdr.java diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index cb2c9b72c6eb..c147bccc19b5 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -67,8 +67,26 @@ </intent-filter> </receiver> - <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmin" - android:permission="android.permission.BIND_DEVICE_ADMIN"> + <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin1" + android:permission="android.permission.BIND_DEVICE_ADMIN"> + <meta-data android:name="android.app.device_admin" + android:resource="@xml/device_admin_sample" /> + <intent-filter> + <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> + </intent-filter> + </receiver> + + <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" + android:permission="android.permission.BIND_DEVICE_ADMIN"> + <meta-data android:name="android.app.device_admin" + android:resource="@xml/device_admin_sample" /> + <intent-filter> + <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" /> + </intent-filter> + </receiver> + + <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin3" + android:permission="android.permission.BIND_DEVICE_ADMIN"> <meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_sample" /> <intent-filter> diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java index e677475f5907..e677475f5907 100644 --- a/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java +++ b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java index c599fe3e5b76..c599fe3e5b76 100644 --- a/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java +++ b/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java diff --git a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java index 19ee00036b61..19ee00036b61 100644 --- a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java +++ b/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java deleted file mode 100644 index ca270e7a4b2a..000000000000 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.devicepolicy; - -import android.app.admin.DeviceAdminReceiver; -import android.app.admin.DevicePolicyManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; - -/** - * Tests for application restrictions persisting via profile owner: - * make -j FrameworksServicesTests - * runtest --path frameworks/base/services/tests/servicestests/ \ - * src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java - */ -public class ApplicationRestrictionsTest extends AndroidTestCase { - - static DevicePolicyManager sDpm; - static ComponentName sAdminReceiver; - private static final String RESTRICTED_APP = "com.example.restrictedApp"; - static boolean sAddBack = false; - - public static class AdminReceiver extends DeviceAdminReceiver { - - @Override - public void onDisabled(Context context, Intent intent) { - if (sAddBack) { - sDpm.setActiveAdmin(sAdminReceiver, false); - sAddBack = false; - } - - super.onDisabled(context, intent); - } - } - - @Override - public void setUp() { - final Context context = getContext(); - sAdminReceiver = new ComponentName(mContext.getPackageName(), - AdminReceiver.class.getName()); - sDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); - Settings.Secure.putInt(context.getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE, 0); - sDpm.setProfileOwner(sAdminReceiver, "Test", UserHandle.myUserId()); - Settings.Secure.putInt(context.getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE, 1); - // Remove the admin if already registered. It's async, so add it back - // when the admin gets a broadcast. Otherwise add it back right away. - if (sDpm.isAdminActive(sAdminReceiver)) { - sAddBack = true; - sDpm.removeActiveAdmin(sAdminReceiver); - } else { - sDpm.setActiveAdmin(sAdminReceiver, false); - } - } - - @Override - public void tearDown() { - Settings.Secure.putInt(getContext().getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE, 0); - sDpm.removeActiveAdmin(sAdminReceiver); - Settings.Secure.putInt(getContext().getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE, 1); - } - - public void testSettingRestrictions() { - Bundle restrictions = new Bundle(); - restrictions.putString("KEY_STRING", "Foo"); - assertNotNull(sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP)); - sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions); - Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP); - assertNotNull(returned); - assertEquals(returned.size(), 1); - assertEquals(returned.get("KEY_STRING"), "Foo"); - sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle()); - returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP); - assertEquals(returned.size(), 0); - } - - public void testRestrictionTypes() { - Bundle restrictions = new Bundle(); - restrictions.putString("KEY_STRING", "Foo"); - restrictions.putInt("KEY_INT", 7); - restrictions.putBoolean("KEY_BOOLEAN", true); - restrictions.putBoolean("KEY_BOOLEAN_2", false); - restrictions.putString("KEY_STRING_2", "Bar"); - restrictions.putStringArray("KEY_STR_ARRAY", new String[] { "Foo", "Bar" }); - sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions); - Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP); - assertTrue(returned.getBoolean("KEY_BOOLEAN")); - assertFalse(returned.getBoolean("KEY_BOOLEAN_2")); - assertFalse(returned.getBoolean("KEY_BOOLEAN_3")); - assertEquals(returned.getInt("KEY_INT"), 7); - assertTrue(returned.get("KEY_BOOLEAN") instanceof Boolean); - assertTrue(returned.get("KEY_INT") instanceof Integer); - assertEquals(returned.get("KEY_STRING"), "Foo"); - assertEquals(returned.get("KEY_STRING_2"), "Bar"); - assertTrue(returned.getStringArray("KEY_STR_ARRAY") instanceof String[]); - sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle()); - } - - public void testTextEscaping() { - String fancyText = "<This contains XML/> <JSON> " - + "{ \"One\": { \"OneOne\": \"11\", \"OneTwo\": \"12\" }, \"Two\": \"2\" } <JSON/>"; - Bundle restrictions = new Bundle(); - restrictions.putString("KEY_FANCY_TEXT", fancyText); - sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions); - Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP); - assertEquals(returned.getString("KEY_FANCY_TEXT"), fancyText); - } -} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index cb439ebefbbc..c6c74979f6ef 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -19,10 +19,11 @@ import com.android.internal.widget.LockPatternUtils; import android.app.IActivityManager; import android.app.NotificationManager; +import android.app.backup.IBackupManager; import android.content.Context; -import android.content.pm.PackageManager; +import android.content.pm.IPackageManager; +import android.media.IAudioService; import android.os.Looper; -import android.os.PowerManager.WakeLock; import android.os.PowerManagerInternal; import android.os.UserHandle; import android.os.UserManager; @@ -45,9 +46,9 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi public static final String DEVICE_OWNER_FILE = "device_owner2.xml"; public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml"; - final private File mLegacyFile; - final private File mDeviceOwnerFile; - final private File mProfileOwnerBase; + private final File mLegacyFile; + private final File mDeviceOwnerFile; + private final File mProfileOwnerBase; public OwnersTestable(Context context, File dataDir) { super(context); @@ -72,121 +73,169 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } } - public final File dataDir; - public final File systemUserDataDir; - public final File secondUserDataDir; + public final DpmMockContext context; public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) { - super(context); - this.dataDir = dataDir; + this(new MockInjector(context, dataDir)); + } - systemUserDataDir = new File(dataDir, "user0"); - DpmTestUtils.clearDir(dataDir); + private DevicePolicyManagerServiceTestable(MockInjector injector) { + super(injector); + this.context = injector.context; + } - secondUserDataDir = new File(dataDir, "user" + DpmMockContext.CALLER_USER_HANDLE); - DpmTestUtils.clearDir(secondUserDataDir); + private static class MockInjector extends Injector { - when(getContext().environment.getUserSystemDirectory( - eq(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(secondUserDataDir); - } + public final DpmMockContext context; - @Override - DpmMockContext getContext() { - return (DpmMockContext) super.getContext(); - } + public final File dataDir; - @Override - protected Owners newOwners() { - return new OwnersTestable(getContext(), dataDir); - } + public final File systemUserDataDir; + public final File secondUserDataDir; - @Override - protected UserManager getUserManager() { - return getContext().userManager; - } + private MockInjector(DpmMockContext context, File dataDir) { + super(context); + this.context = context; + this.dataDir = dataDir; - @Override - protected PackageManager getPackageManager() { - return getContext().packageManager; - } + systemUserDataDir = new File(dataDir, "user0"); + DpmTestUtils.clearDir(dataDir); - @Override - protected PowerManagerInternal getPowerManagerInternal() { - return getContext().powerManagerInternal; - } + secondUserDataDir = new File(dataDir, "user" + DpmMockContext.CALLER_USER_HANDLE); + DpmTestUtils.clearDir(secondUserDataDir); - @Override - protected NotificationManager getNotificationManager() { - return getContext().notificationManager; - } + when(context.environment.getUserSystemDirectory( + eq(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(secondUserDataDir); + } - @Override - protected IWindowManager newIWindowManager() { - return getContext().iwindowManager; - } + @Override + Owners newOwners() { + return new OwnersTestable(context, dataDir); + } - @Override - protected IActivityManager getIActivityManager() { - return getContext().iactivityManager; - } + @Override + UserManager getUserManager() { + return context.userManager; + } - @Override - protected LockPatternUtils newLockPatternUtils(Context context) { - return getContext().lockPatternUtils; - } + @Override + PowerManagerInternal getPowerManagerInternal() { + return context.powerManagerInternal; + } - @Override - protected Looper getMyLooper() { - return Looper.getMainLooper(); - } + @Override + NotificationManager getNotificationManager() { + return context.notificationManager; + } - @Override - String getDevicePolicyFilePathForSystemUser() { - return systemUserDataDir.getAbsolutePath(); - } + @Override + IWindowManager getIWindowManager() { + return context.iwindowManager; + } - @Override - long binderClearCallingIdentity() { - return getContext().binder.clearCallingIdentity(); - } + @Override + IActivityManager getIActivityManager() { + return context.iactivityManager; + } - @Override - void binderRestoreCallingIdentity(long token) { - getContext().binder.restoreCallingIdentity(token); - } + @Override + IPackageManager getIPackageManager() { + return context.ipackageManager; + } - @Override - int binderGetCallingUid() { - return getContext().binder.getCallingUid(); - } + @Override + IBackupManager getIBackupManager() { + return context.ibackupManager; + } - @Override - int binderGetCallingPid() { - return getContext().binder.getCallingPid(); - } + @Override + IAudioService getIAudioService() { + return context.iaudioService; + } - @Override - UserHandle binderGetCallingUserHandle() { - return getContext().binder.getCallingUserHandle(); - } + @Override + Looper getMyLooper() { + return Looper.getMainLooper(); + } - @Override - boolean binderIsCallingUidMyUid() { - return getContext().binder.isCallerUidMyUid(); - } + @Override + LockPatternUtils newLockPatternUtils() { + return context.lockPatternUtils; + } - @Override - File environmentGetUserSystemDirectory(int userId) { - return getContext().environment.getUserSystemDirectory(userId); - } + @Override + String getDevicePolicyFilePathForSystemUser() { + return systemUserDataDir.getAbsolutePath(); + } - @Override - WakeLock powerManagerNewWakeLock(int levelAndFlags, String tag) { - return getContext().powerManager.newWakeLock(levelAndFlags, tag); - } + @Override + long binderClearCallingIdentity() { + return context.binder.clearCallingIdentity(); + } + + @Override + void binderRestoreCallingIdentity(long token) { + context.binder.restoreCallingIdentity(token); + } + + @Override + int binderGetCallingUid() { + return context.binder.getCallingUid(); + } + + @Override + int binderGetCallingPid() { + return context.binder.getCallingPid(); + } + + @Override + UserHandle binderGetCallingUserHandle() { + return context.binder.getCallingUserHandle(); + } + + @Override + boolean binderIsCallingUidMyUid() { + return context.binder.isCallerUidMyUid(); + } + + @Override + File environmentGetUserSystemDirectory(int userId) { + return context.environment.getUserSystemDirectory(userId); + } + + @Override + void powerManagerGoToSleep(long time, int reason, int flags) { + context.powerManager.goToSleep(time, reason, flags); + } + + @Override + boolean systemPropertiesGetBoolean(String key, boolean def) { + return context.systemProperties.getBoolean(key, def); + } + + @Override + long systemPropertiesGetLong(String key, long def) { + return context.systemProperties.getLong(key, def); + } - @Override - void powerManagerGoToSleep(long time, int reason, int flags) { - getContext().powerManager.goToSleep(time, reason, flags); + @Override + String systemPropertiesGet(String key, String def) { + return context.systemProperties.get(key, def); + } + + @Override + String systemPropertiesGet(String key) { + return context.systemProperties.get(key); + } + + @Override + void systemPropertiesSet(String key, String value) { + context.systemProperties.set(key, value); + } + + @Override + boolean userManagerIsSplitSystemUser() { + return context.userManagerForMock.isSplitSystemUser(); + } } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 7cce56cea39e..0072f526bd95 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -13,33 +13,48 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.server.devicepolicy; import com.android.server.LocalServices; +import android.Manifest.permission; +import android.app.Activity; import android.app.admin.DeviceAdminReceiver; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.content.pm.PackageInfo; +import android.content.pm.UserInfo; import android.os.UserHandle; +import android.util.Pair; import org.mockito.ArgumentCaptor; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** - * Tests for {@link DevicePolicyManager} and {@link DevicePolicyManagerService}. + * Tests for DevicePolicyManager( and DevicePolicyManagerService). * m FrameworksServicesTests && adb install \ @@ -51,9 +66,13 @@ import static org.mockito.Mockito.when; */ public class DevicePolicyManagerTest extends DpmTestBase { + private DpmMockContext mContext; public DevicePolicyManager dpm; public DevicePolicyManagerServiceTestable dpms; + public ComponentName admin1; + public ComponentName admin2; + public ComponentName admin3; @Override protected void setUp() throws Exception { @@ -67,9 +86,142 @@ public class DevicePolicyManagerTest extends DpmTestBase { LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir); dpm = new DevicePolicyManagerTestable(mContext, dpms); + + admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class); + admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class); + admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class); + + setUpPackageManagerForAdmin(admin1); + setUpPackageManagerForAdmin(admin2); + setUpPackageManagerForAdmin(admin3); + + setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); + setUpPackageInfo(); + setUpUserManager(); } - public void testHasNoFeature() { + /** + * Set up a mock result for {@link PackageManager#queryBroadcastReceivers}. We'll return + * the actual ResolveInfo for the admin component, but we need to mock PM so it'll return + * it for user {@link DpmMockContext#CALLER_USER_HANDLE}. + */ + private void setUpPackageManagerForAdmin(ComponentName admin) { + final Intent resolveIntent = new Intent(); + resolveIntent.setComponent(admin); + final List<ResolveInfo> realResolveInfo = + mRealTestContext.getPackageManager().queryBroadcastReceivers( + resolveIntent, + PackageManager.GET_META_DATA); + assertNotNull(realResolveInfo); + assertEquals(1, realResolveInfo.size()); + + // We need to rewrite the UID in the activity info. + realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID; + + doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers( + MockUtils.checkIntentComponent(admin), + eq(PackageManager.GET_META_DATA + | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(DpmMockContext.CALLER_USER_HANDLE) + ); + } + + /** + * Set up a mock result for {@link IPackageManager#getApplicationInfo} for user + * {@link DpmMockContext#CALLER_USER_HANDLE}. + */ + private void setUpApplicationInfo(int enabledSetting) throws Exception { + final ApplicationInfo ai = mRealTestContext.getPackageManager().getApplicationInfo( + admin1.getPackageName(), + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); + + ai.enabledSetting = enabledSetting; + + doReturn(ai).when(mContext.ipackageManager).getApplicationInfo( + eq(admin1.getPackageName()), + eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(DpmMockContext.CALLER_USER_HANDLE)); + } + + /** + * Set up a mock result for {@link IPackageManager#getPackageInfo(String, int, int)} for user + * {@link DpmMockContext#CALLER_USER_HANDLE} as well as the system user. + */ + private void setUpPackageInfo() throws Exception { + final PackageInfo pi = mRealTestContext.getPackageManager().getPackageInfo( + admin1.getPackageName(), 0); + assertTrue(pi.applicationInfo.flags != 0); + + doReturn(pi).when(mContext.ipackageManager).getPackageInfo( + eq(admin1.getPackageName()), + eq(0), + eq(DpmMockContext.CALLER_USER_HANDLE)); + doReturn(pi).when(mContext.ipackageManager).getPackageInfo( + eq(admin1.getPackageName()), + eq(0), + eq(UserHandle.USER_SYSTEM)); + } + + private void setUpUserManager() { + // Emulate UserManager.set/getApplicationRestriction(). + final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>(); + + // UM.setApplicationRestrictions() will save to appRestrictions. + doAnswer(new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + String pkg = (String) invocation.getArguments()[0]; + Bundle bundle = (Bundle) invocation.getArguments()[1]; + UserHandle user = (UserHandle) invocation.getArguments()[2]; + + appRestrictions.put(Pair.create(pkg, user), bundle); + + return null; + } + }).when(mContext.userManager).setApplicationRestrictions( + anyString(), any(Bundle.class), any(UserHandle.class)); + + // UM.getApplicationRestrictions() will read from appRestrictions. + doAnswer(new Answer<Bundle>() { + @Override + public Bundle answer(InvocationOnMock invocation) throws Throwable { + String pkg = (String) invocation.getArguments()[0]; + UserHandle user = (UserHandle) invocation.getArguments()[1]; + + return appRestrictions.get(Pair.create(pkg, user)); + } + }).when(mContext.userManager).getApplicationRestrictions( + anyString(), any(UserHandle.class)); + + // System user is always running. + when(mContext.userManager.isUserRunning(MockUtils.checkUserHandle(UserHandle.USER_SYSTEM))) + .thenReturn(true); + + // Set up (default) UserInfo for CALLER_USER_HANDLE. + final UserInfo uh = new UserInfo(DpmMockContext.CALLER_USER_HANDLE, + "user" + DpmMockContext.CALLER_USER_HANDLE, 0); + + when(mContext.userManager.getUserInfo(eq(DpmMockContext.CALLER_USER_HANDLE))) + .thenReturn(uh); + } + + private void setAsProfileOwner(ComponentName admin) { + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + + final UserInfo uh = new UserInfo(DpmMockContext.CALLER_USER_HANDLE, "user", 0); + + // DO needs to be an DA. + dpm.setActiveAdmin(admin, /* replace =*/ false); + + // Fire! + assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE)); + + // Check + assertEquals(admin1, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE)); + } + + public void testHasNoFeature() throws Exception { when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) .thenReturn(false); @@ -84,13 +236,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { * Caller doesn't have proper permissions. */ public void testSetActiveAdmin_SecurityException() { - final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class); - // 1. Failure cases. // Caller doesn't have MANAGE_DEVICE_ADMINS. try { - dpm.setActiveAdmin(admin, false); + dpm.setActiveAdmin(admin1, false); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } @@ -98,62 +248,345 @@ public class DevicePolicyManagerTest extends DpmTestBase { // Caller has MANAGE_DEVICE_ADMINS, but for different user. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); try { - dpm.setActiveAdmin(admin, false, DpmMockContext.CALLER_USER_HANDLE + 1); + dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1); fail("Didn't throw SecurityException"); } catch (SecurityException expected) { } } - public void testSetActiveAdmin() { - final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class); + /** + * Test for: + * {@link DevicePolicyManager#setActiveAdmin} + * with replace=false and replace=true + * {@link DevicePolicyManager#isAdminActive} + * {@link DevicePolicyManager#isAdminActiveAsUser} + * {@link DevicePolicyManager#getActiveAdmins} + * {@link DevicePolicyManager#getActiveAdminsAsUser} + */ + public void testSetActiveAdmin() throws Exception { + // 1. Make sure the caller has proper permissions. + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // 2. Call the API. + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + // 3. Verify internal calls. + + // Check if the boradcast is sent. + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + verify(mContext.spiedContext).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + + verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting( + eq(admin1.getPackageName()), + eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), + eq(PackageManager.DONT_KILL_APP), + eq(DpmMockContext.CALLER_USER_HANDLE), + anyString()); + + // TODO Verify other calls too. + + // Make sure it's active admin1. + assertTrue(dpm.isAdminActive(admin1)); + assertFalse(dpm.isAdminActive(admin2)); + assertFalse(dpm.isAdminActive(admin3)); + + // But not admin1 for a different user. + + // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL. + // (Because we're checking a different user's status from CALLER_USER_HANDLE.) + mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); + + assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1)); + assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1)); + + mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); + + // Next, add one more admin. + // Before doing so, update the application info, now it's enabled. + setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); + + dpm.setActiveAdmin(admin2, /* replace =*/ false); - // 1. Prepare mock package manager (and other mocks) + // Now we have two admins. + assertTrue(dpm.isAdminActive(admin1)); + assertTrue(dpm.isAdminActive(admin2)); + assertFalse(dpm.isAdminActive(admin3)); + // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called + // again. (times(1) because it was previously called for admin1) + verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting( + eq(admin1.getPackageName()), + eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), + eq(PackageManager.DONT_KILL_APP), + eq(DpmMockContext.CALLER_USER_HANDLE), + anyString()); + + // 4. Add the same admin1 again without replace, which should throw. + try { + dpm.setActiveAdmin(admin1, /* replace =*/ false); + fail("Didn't throw"); + } catch (IllegalArgumentException expected) { + } + + // 5. Add the same admin1 again with replace, which should succeed. + dpm.setActiveAdmin(admin1, /* replace =*/ true); + + // TODO make sure it's replaced. + + // 6. Test getActiveAdmins() + List<ComponentName> admins = dpm.getActiveAdmins(); + assertEquals(2, admins.size()); + assertEquals(admin1, admins.get(0)); + assertEquals(admin2, admins.get(1)); + + // Another user has no admins. + mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL"); + + assertEquals(0, DpmTestUtils.getListSizeAllowingNull( + dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1))); + + mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL"); + } + + /** + * Test for: + * {@link DevicePolicyManager#setActiveAdmin} + * with replace=false + */ + public void testSetActiveAdmin_twiceWithoutReplace() throws Exception { + // 1. Make sure the caller has proper permissions. mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); - // Create ResolveInfo for the admin. - final Intent resolveIntent = new Intent(); - resolveIntent.setComponent(admin); - final List<ResolveInfo> realResolveInfo = - mRealTestContext.getPackageManager().queryBroadcastReceivers( - resolveIntent, - PackageManager.GET_META_DATA - | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); - assertNotNull(realResolveInfo); - assertEquals(1, realResolveInfo.size()); + dpm.setActiveAdmin(admin1, /* replace =*/ false); + assertTrue(dpm.isAdminActive(admin1)); - // We need to rewrite the UID in the activity info. - realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID; + // Add the same admin1 again without replace, which should throw. + try { + dpm.setActiveAdmin(admin1, /* replace =*/ false); + fail("Didn't throw"); + } catch (IllegalArgumentException expected) { + } + } - doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers( - any(Intent.class), // TODO check the intent too. - eq(PackageManager.GET_META_DATA - | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), - eq(DpmMockContext.CALLER_USER_HANDLE) - ); + /** + * Test for: + * {@link DevicePolicyManager#removeActiveAdmin} + */ + public void testRemoveActiveAdmin_SecurityException() { + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); - // 2. Everything is ready; call the method. - dpm.setActiveAdmin(admin, false); + // Add admin. - // 3. Verify internal calls. + dpm.setActiveAdmin(admin1, /* replace =*/ false); - // Check if the boradcast is sent. - final ArgumentCaptor<Intent> intentCap = ArgumentCaptor.forClass(Intent.class); - final ArgumentCaptor<UserHandle> uhCap = ArgumentCaptor.forClass(UserHandle.class); + assertTrue(dpm.isAdminActive(admin1)); + + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + // Directly call the DPMS method with a different userid, which should fail. + try { + dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + + // Try to remove active admin with a different caller userid should fail too, without + // having MANAGE_DEVICE_ADMINS. + mContext.callerPermissions.clear(); + + mContext.binder.callingUid = 1234567; + try { + dpm.removeActiveAdmin(admin1); + fail("Didn't throw SecurityException"); + } catch (SecurityException expected) { + } + } + + /** + * Test for: + * {@link DevicePolicyManager#removeActiveAdmin} + */ + public void testRemoveActiveAdmin_fromDifferentUserWithMINTERACT_ACROSS_USERS_FULL() { + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // Add admin1. + + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + assertTrue(dpm.isAdminActive(admin1)); + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // Different user, but should work, because caller has proper permissions. + mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); + mContext.binder.callingUid = 1234567; + dpm.removeActiveAdmin(admin1); + + assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // TODO DO Still can't be removed in this case. + } + + /** + * Test for: + * {@link DevicePolicyManager#removeActiveAdmin} + */ + public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() { + // Need MANAGE_DEVICE_ADMINS for setActiveAdmin. We'll remove it later. + mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS); + + // Add admin1. + + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + assertTrue(dpm.isAdminActive(admin1)); + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // Broadcast from saveSettingsLocked(). + verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); + + // Remove. No permissions, but same user, so it'll work. + mContext.callerPermissions.clear(); + dpm.removeActiveAdmin(admin1); + + final ArgumentCaptor<BroadcastReceiver> brCap = + ArgumentCaptor.forClass(BroadcastReceiver.class); + + // Is removing now, but not removed yet. + assertTrue(dpm.isAdminActive(admin1)); + assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + verify(mContext.spiedContext).sendOrderedBroadcastAsUser( + MockUtils.checkIntentAction( + DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED), + MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE), + isNull(String.class), + brCap.capture(), + eq(dpms.mHandler), + eq(Activity.RESULT_OK), + isNull(String.class), + isNull(Bundle.class)); + + brCap.getValue().onReceive(mContext, null); + + assertFalse(dpm.isAdminActive(admin1)); + assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE)); + + // Again broadcast from saveSettingsLocked(). verify(mContext.spiedContext, times(2)).sendBroadcastAsUser( - intentCap.capture(), + MockUtils.checkIntentAction( + DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE)); - // First call from saveSettingsLocked(). - assertEquals(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED, - intentCap.getAllValues().get(0).getAction()); + // TODO Check other internal calls. + } - // Second call from setActiveAdmin/sendAdminCommandLocked() - assertEquals(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED, - intentCap.getAllValues().get(1).getAction()); + /** + * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs + * successfully. + */ + public void testSetDeviceOwner() throws Exception { + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); - // TODO Verify other calls too. + // Call from a process on the system user. + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + + // DO needs to be an DA. + dpm.setActiveAdmin(admin1, /* replace =*/ false); + + // Fire! + assertTrue(dpm.setDeviceOwner(admin1.getPackageName(), "owner-name")); + + // Verify internal calls. + verify(mContext.iactivityManager, times(1)).updateDeviceOwner( + eq(admin1.getPackageName())); + + // TODO We should check if the caller has called clearCallerIdentity(). + verify(mContext.ibackupManager, times(1)).setBackupServiceActive( + eq(UserHandle.USER_SYSTEM), eq(false)); + + verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( + MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED), + MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); + + assertEquals(admin1.getPackageName(), dpm.getDeviceOwner()); + + // TODO Test getDeviceOwnerName() too. To do so, we need to change + // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable. } -} + /** + * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist. + */ + public void testSetDeviceOwner_noSuchPackage() { + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); + + // Call from a process on the system user. + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + + // DO needs to be an DA. + dpm.setActiveAdmin(admin1, /* replace =*/ false); + try { + dpm.setDeviceOwner("a.b.c"); + fail("Didn't throw IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + } + } + + public void testSetDeviceOwner_failures() throws Exception { + // TODO Test more failure cases. Basically test all chacks in enforceCanSetDeviceOwner(). + } + + public void testSetProfileOwner() throws Exception { + setAsProfileOwner(admin1); + } + + public void testSetProfileOwner_failures() throws Exception { + // TODO Test more failure cases. Basically test all chacks in enforceCanSetProfileOwner(). + } + + public void testSetGetApplicationRestriction() { + setAsProfileOwner(admin1); + + { + Bundle rest = new Bundle(); + rest.putString("KEY_STRING", "Foo1"); + dpm.setApplicationRestrictions(admin1, "pkg1", rest); + } + + { + Bundle rest = new Bundle(); + rest.putString("KEY_STRING", "Foo2"); + dpm.setApplicationRestrictions(admin1, "pkg2", rest); + } + + { + Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg1"); + assertNotNull(returned); + assertEquals(returned.size(), 1); + assertEquals(returned.get("KEY_STRING"), "Foo1"); + } + + { + Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg2"); + assertNotNull(returned); + assertEquals(returned.size(), 1); + assertEquals(returned.get("KEY_STRING"), "Foo2"); + } + + dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle()); + assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 864431157660..3b30a37bd2c0 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -20,11 +20,14 @@ import com.android.internal.widget.LockPatternUtils; import android.app.IActivityManager; import android.app.NotificationManager; +import android.app.backup.IBackupManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.media.IAudioService; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager.WakeLock; @@ -34,6 +37,8 @@ import android.os.UserManager; import android.test.mock.MockContext; import android.view.IWindowManager; +import org.junit.Assert; + import java.io.File; import java.util.ArrayList; import java.util.List; @@ -51,11 +56,16 @@ public class DpmMockContext extends MockContext { public static final int CALLER_USER_HANDLE = 20; /** - * UID of the caller. + * UID corresponding to {@link #CALLER_USER_HANDLE}. */ public static final int CALLER_UID = UserHandle.PER_USER_RANGE * CALLER_USER_HANDLE + 123; /** + * UID used when a caller is on the system user. + */ + public static final int CALLER_SYSTEM_USER_UID = 123; + + /** * PID of the caller. */ public static final int CALLER_PID = 22222; @@ -71,27 +81,27 @@ public class DpmMockContext extends MockContext { public static final int SYSTEM_PID = 11111; public static class MockBinder { - int mCallingUid = CALLER_UID; - int mCallingPid = CALLER_PID; + public int callingUid = CALLER_UID; + public int callingPid = CALLER_PID; public long clearCallingIdentity() { - final long token = (((long) mCallingUid) << 32) | (mCallingPid); - mCallingUid = SYSTEM_UID; - mCallingPid = SYSTEM_PID; + final long token = (((long) callingUid) << 32) | (callingPid); + callingUid = SYSTEM_UID; + callingPid = SYSTEM_PID; return token; } public void restoreCallingIdentity(long token) { - mCallingUid = (int) (token >> 32); - mCallingPid = (int) token; + callingUid = (int) (token >> 32); + callingPid = (int) token; } public int getCallingUid() { - return mCallingUid; + return callingUid; } public int getCallingPid() { - return mCallingPid; + return callingPid; } public UserHandle getCallingUserHandle() { @@ -99,7 +109,7 @@ public class DpmMockContext extends MockContext { } public boolean isCallerUidMyUid() { - return mCallingUid == SYSTEM_UID; + return callingUid == SYSTEM_UID; } } @@ -118,6 +128,33 @@ public class DpmMockContext extends MockContext { } } + public static class SystemPropertiesForMock { + public boolean getBoolean(String key, boolean def) { + return false; + } + + public long getLong(String key, long def) { + return 0; + } + + public String get(String key, String def) { + return null; + } + + public String get(String key) { + return null; + } + + public void set(String key, String value) { + } + } + + public static class UserManagerForMock { + public boolean isSplitSystemUser() { + return false; + } + } + public final Context realTestContext; /** @@ -129,12 +166,17 @@ public class DpmMockContext extends MockContext { public final MockBinder binder; public final EnvironmentForMock environment; + public final SystemPropertiesForMock systemProperties; public final UserManager userManager; + public final UserManagerForMock userManagerForMock; public final PowerManagerForMock powerManager; public final PowerManagerInternal powerManagerInternal; public final NotificationManager notificationManager; public final IWindowManager iwindowManager; public final IActivityManager iactivityManager; + public final IPackageManager ipackageManager; + public final IBackupManager ibackupManager; + public final IAudioService iaudioService; public final LockPatternUtils lockPatternUtils; /** Note this is a partial mock, not a real mock. */ @@ -146,12 +188,17 @@ public class DpmMockContext extends MockContext { realTestContext = context; binder = new MockBinder(); environment = mock(EnvironmentForMock.class); + systemProperties= mock(SystemPropertiesForMock.class); userManager = mock(UserManager.class); + userManagerForMock = mock(UserManagerForMock.class); powerManager = mock(PowerManagerForMock.class); powerManagerInternal = mock(PowerManagerInternal.class); notificationManager = mock(NotificationManager.class); iwindowManager = mock(IWindowManager.class); iactivityManager = mock(IActivityManager.class); + ipackageManager = mock(IPackageManager.class); + ibackupManager = mock(IBackupManager.class); + iaudioService = mock(IAudioService.class); lockPatternUtils = mock(LockPatternUtils.class); // Package manager is huge, so we use a partial mock instead. @@ -172,6 +219,11 @@ public class DpmMockContext extends MockContext { } @Override + public String getSystemServiceName(Class<?> serviceClass) { + return realTestContext.getSystemServiceName(serviceClass); + } + + @Override public PackageManager getPackageManager() { return packageManager; } @@ -244,6 +296,13 @@ public class DpmMockContext extends MockContext { @Override public void sendBroadcastAsUser(Intent intent, UserHandle user) { + if (binder.callingPid != SYSTEM_PID) { + // Unless called as the system process, can only call if the target user is the + // calling user. + // (The actual check is more complex; we may need to change it later.) + Assert.assertEquals(UserHandle.getUserId(binder.getCallingUid()), user.getIdentifier()); + } + spiedContext.sendBroadcastAsUser(intent, user); } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index 77270c8cec55..6f9f6ab7c5b9 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -21,7 +21,7 @@ import android.test.AndroidTestCase; import java.io.File; -public class DpmTestBase extends AndroidTestCase { +public abstract class DpmTestBase extends AndroidTestCase { public static final String TAG = "DpmTest"; protected Context mRealTestContext; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java index a8e2c3ce4831..44a851abe476 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java @@ -23,6 +23,7 @@ import android.util.Printer; import org.junit.Assert; import java.io.File; +import java.util.List; public class DpmTestUtils { private DpmTestUtils() { @@ -33,6 +34,11 @@ public class DpmTestUtils { Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir)); } dir.mkdirs(); + Log.i(DpmTestBase.TAG, "Created " + dir); + } + + public static int getListSizeAllowingNull(List<?> list) { + return list == null ? 0 : list.size(); } public static Printer LOG_PRINTER = new Printer() { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java index c47d19447395..08293a259145 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java @@ -17,5 +17,11 @@ package com.android.server.devicepolicy; import android.app.admin.DeviceAdminReceiver; -public class DummyDeviceAdmin extends DeviceAdminReceiver { +public class DummyDeviceAdmins { + public static class Admin1 extends DeviceAdminReceiver { + } + public static class Admin2 extends DeviceAdminReceiver { + } + public static class Admin3 extends DeviceAdminReceiver { + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java index f2a2bf7e5e13..5008fbfa3b10 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java @@ -17,6 +17,8 @@ package com.android.server.devicepolicy; import com.google.common.base.Objects; +import android.content.ComponentName; +import android.content.Intent; import android.os.UserHandle; import org.hamcrest.BaseMatcher; @@ -44,4 +46,35 @@ public class MockUtils { return Mockito.argThat(m); } + public static Intent checkIntentComponent(final ComponentName component) { + final Matcher<Intent> m = new BaseMatcher<Intent>() { + @Override + public boolean matches(Object item) { + if (item == null) return false; + return Objects.equal(((Intent) item).getComponent(), component); + } + + @Override + public void describeTo(Description description) { + description.appendText("Intent: component=\"" + component + "\""); + } + }; + return Mockito.argThat(m); + } + + public static Intent checkIntentAction(final String action) { + final Matcher<Intent> m = new BaseMatcher<Intent>() { + @Override + public boolean matches(Object item) { + if (item == null) return false; + return Objects.equal(((Intent) item).getAction(), action); + } + + @Override + public void describeTo(Description description) { + description.appendText("Intent: action=\"" + action + "\""); + } + }; + return Mockito.argThat(m); + } } diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 8779462e073e..a8f2aca43708 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -14,6 +14,7 @@ package android.telecom; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.ComponentName; import android.content.Context; @@ -116,6 +117,15 @@ public class TelecomManager { "android.telecom.action.PHONE_ACCOUNT_REGISTERED"; /** + * The {@link android.content.Intent} action used indicate that a phone account was + * just unregistered. + * @hide + */ + @SystemApi + public static final String ACTION_PHONE_ACCOUNT_UNREGISTERED = + "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED"; + + /** * Activity action: Shows a dialog asking the user whether or not they want to replace the * current default Dialer with the one specified in * {@link #EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME}. @@ -472,9 +482,12 @@ public class TelecomManager { * <p> * If no {@link PhoneAccount} fits the criteria above, this method will return {@code null}. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @param uriScheme The URI scheme. * @return The {@link PhoneAccountHandle} corresponding to the account to be used. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) { try { if (isServiceConnected()) { @@ -606,9 +619,12 @@ public class TelecomManager { * calls. The returned list includes only those accounts which have been explicitly enabled * by the user. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @see #EXTRA_PHONE_ACCOUNT_HANDLE * @return A list of {@code PhoneAccountHandle} objects. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public List<PhoneAccountHandle> getCallCapablePhoneAccounts() { return getCallCapablePhoneAccounts(false); } @@ -881,9 +897,12 @@ public class TelecomManager { * Return whether a given phone number is the configured voicemail number for a * particular phone account. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @param accountHandle The handle for the account to check the voicemail number against * @param number The number to look up. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) { try { if (isServiceConnected()) { @@ -899,10 +918,13 @@ public class TelecomManager { /** * Return the voicemail number for a given phone account. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @param accountHandle The handle for the phone account. * @return The voicemail number for the phone account, and {@code null} if one has not been * configured. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(PhoneAccountHandle accountHandle) { try { if (isServiceConnected()) { @@ -918,9 +940,12 @@ public class TelecomManager { /** * Return the line 1 phone number for given phone account. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @param accountHandle The handle for the account retrieve a number for. * @return A string representation of the line 1 phone number. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1Number(PhoneAccountHandle accountHandle) { try { if (isServiceConnected()) { @@ -940,6 +965,7 @@ public class TelecomManager { * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} * </p> */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInCall() { try { if (isServiceConnected()) { @@ -1031,7 +1057,10 @@ public class TelecomManager { /** * Silences the ringer if a ringing call exists. + * + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger() { try { if (isServiceConnected()) { @@ -1136,9 +1165,12 @@ public class TelecomManager { * Requires that the method-caller be set as the system dialer app. * </p> * + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * * @param dialString The digits to dial. * @return True if the digits were processed as an MMI code, false otherwise. */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String dialString) { ITelecomService service = getTelecomService(); if (service != null) { @@ -1159,10 +1191,13 @@ public class TelecomManager { * Requires that the method-caller be set as the system dialer app. * </p> * + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * * @param accountHandle The handle for the account the MMI code should apply to. * @param dialString The digits to dial. * @return True if the digits were processed as an MMI code, false otherwise. */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String dialString, PhoneAccountHandle accountHandle) { ITelecomService service = getTelecomService(); if (service != null) { @@ -1177,11 +1212,14 @@ public class TelecomManager { } /** + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * * @param accountHandle The handle for the account to derive an adn query URI for or * {@code null} to return a URI which will use the default account. * @return The URI (with the content:// scheme) specific to the specified {@link PhoneAccount} * for the the content retrieve. */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) { ITelecomService service = getTelecomService(); if (service != null && accountHandle != null) { @@ -1199,7 +1237,10 @@ public class TelecomManager { * <p> * Requires that the method-caller be set as the system dialer app. * </p> + * + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification() { ITelecomService service = getTelecomService(); if (service != null) { @@ -1221,6 +1262,7 @@ public class TelecomManager { * * @param showDialpad Brings up the in-call dialpad as part of showing the in-call screen. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean showDialpad) { ITelecomService service = getTelecomService(); if (service != null) { @@ -1262,6 +1304,7 @@ public class TelecomManager { * @param address The address to make the call to. * @param extras Bundle of extras to use with the call. */ + @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void placeCall(Uri address, Bundle extras) { ITelecomService service = getTelecomService(); if (service != null) { diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 1ff621a6cac9..17c24af8992c 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -63,8 +63,14 @@ import java.util.List; public class MockPackageManager extends PackageManager { @Override - public PackageInfo getPackageInfo(String packageName, int flags) - throws NameNotFoundException { + public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + + /** @hide */ + @Override + public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) + throws NameNotFoundException { throw new UnsupportedOperationException(); } @@ -524,6 +530,14 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, + int flags, String installerPackageName, int userId) { + throw new UnsupportedOperationException(); + } + + @Override public void setInstallerPackageName(String targetPackage, String installerPackageName) { @@ -629,6 +643,15 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** + * @hide - to match hiding in superclass + */ + @Override + public void deletePackageAsUser( + String packageName, IPackageDeleteObserver observer, int flags, int userId) { + throw new UnsupportedOperationException(); + } + @Override public void addPackageToPreferred(String packageName) { throw new UnsupportedOperationException(); @@ -792,7 +815,15 @@ public class MockPackageManager extends PackageManager { * @hide */ @Override - public int installExistingPackage(String packageName) + public int installExistingPackage(String packageName) throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + + /** + * @hide + */ + @Override + public int installExistingPackageAsUser(String packageName, int userId) throws NameNotFoundException { throw new UnsupportedOperationException(); } diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java index 0b43666a5453..8085db72fba5 100644 --- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java +++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java @@ -31,5 +31,7 @@ public class CameraActivity extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.camera_activity); Log.i(TAG, "Activity created"); + Log.i(TAG, "Source: " + + getIntent().getStringExtra("com.android.systemui.camera_launch_source")); } } diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java index 530fe0063954..242d3b2c2a98 100644 --- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java +++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java @@ -17,6 +17,7 @@ package com.google.android.test.cameraprewarm; import android.app.Activity; +import android.graphics.Camera; import android.os.Bundle; import android.util.Log; import android.view.WindowManager; @@ -31,5 +32,7 @@ public class SecureCameraActivity extends Activity { setContentView(R.layout.camera_activity); getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); Log.i(CameraActivity.TAG, "Activity created"); + Log.i(CameraActivity.TAG, "Source: " + + getIntent().getStringExtra("com.android.systemui.camera_launch_source")); } } diff --git a/tests/WindowAnimationJank/Android.mk b/tests/WindowAnimationJank/Android.mk new file mode 100644 index 000000000000..888ae6434516 --- /dev/null +++ b/tests/WindowAnimationJank/Android.mk @@ -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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := WindowAnimationJank + +LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator ub-janktesthelper + +LOCAL_SDK_VERSION := current + +include $(BUILD_PACKAGE) diff --git a/tests/WindowAnimationJank/AndroidManifest.xml b/tests/WindowAnimationJank/AndroidManifest.xml new file mode 100644 index 000000000000..d7aef3348af3 --- /dev/null +++ b/tests/WindowAnimationJank/AndroidManifest.xml @@ -0,0 +1,40 @@ +<?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="android.windowanimationjank"> + + <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" /> + + <application> + <uses-library android:name="android.test.runner"/> + <activity android:name="ElementLayoutActivity" + android:label="ElementLayoutActivity" + android:taskAffinity="android.windowanimationjank.ElementLayoutActivity" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + + <!-- self-instrumenting test package. --> + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="android.windowanimationjank"> + </instrumentation> + +</manifest> diff --git a/tests/WindowAnimationJank/res/layout/flowlayout.xml b/tests/WindowAnimationJank/res/layout/flowlayout.xml new file mode 100644 index 000000000000..f2b559b2dd02 --- /dev/null +++ b/tests/WindowAnimationJank/res/layout/flowlayout.xml @@ -0,0 +1,21 @@ +<?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.windowanimationjank.FlowLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/root_flow_layout" + android:layout_width="fill_parent" + android:layout_height="fill_parent" />
\ No newline at end of file diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java b/tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java new file mode 100644 index 000000000000..3b1fabcb59ec --- /dev/null +++ b/tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java @@ -0,0 +1,159 @@ +/* + * 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.windowanimationjank; + +import java.util.Random; + +import android.app.Activity; +import android.os.Bundle; +import android.view.ViewTreeObserver.OnPreDrawListener; +import android.widget.Chronometer; +import android.widget.RadioButton; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.ToggleButton; + +/* + * Activity with arbitrary number of random UI elements, refresh itself constantly. + */ +public class ElementLayoutActivity extends Activity implements OnPreDrawListener { + public final static String NUM_ELEMENTS_KEY = "num_elements"; + + private final static int DEFAULT_NUM_ELEMENTS = 100; + private final static int BACKGROUND_COLOR = 0xfffff000; + private final static int INDICATOR_COLOR = 0xffff0000; + + private FlowLayout mLayout; + // Use the constant seed in order to get predefined order of elements. + private Random mRandom = new Random(0); + // Blinker indicator for visual feedback that Activity is currently updating. + private TextView mIndicator; + private static float mIndicatorState; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.flowlayout); + + mLayout = (FlowLayout)findViewById(R.id.root_flow_layout); + mLayout.setBackgroundColor(BACKGROUND_COLOR); + + mIndicator = new TextView(this); + mLayout.addView(mIndicator); + mIndicator.setText("***\n***"); + mIndicator.setBackgroundColor(BACKGROUND_COLOR); + mIndicatorState = 0.0f; + + // Need constantly invalidate view in order to get max redraw rate. + mLayout.getViewTreeObserver().addOnPreDrawListener(this); + + // Read requested number of elements in layout. + int numElements = getIntent().getIntExtra(NUM_ELEMENTS_KEY, DEFAULT_NUM_ELEMENTS); + + for (int i = 0; i < numElements; ++i) { + switch (mRandom.nextInt(5)) { + case 0: + createRadioButton(); + break; + case 1: + createToggleButton(); + break; + case 2: + createSwitch(); + break; + case 3: + createTextView(); + break; + case 4: + createChronometer(); + break; + } + } + + setContentView(mLayout); + } + + private void createTextView() { + TextView textView = new TextView(this); + int lineCnt = mRandom.nextInt(4); + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < lineCnt; ++i) { + if (i != 0) { + buffer.append("\n"); + } + buffer.append("Line:" + mRandom.nextInt()); + } + textView.setText(buffer); + mLayout.addView(textView); + } + + private void createRadioButton() { + RadioButton button = new RadioButton(this); + button.setText("RadioButton:" + mRandom.nextInt()); + mLayout.addView(button); + } + + private void createToggleButton() { + ToggleButton button = new ToggleButton(this); + button.setChecked(mRandom.nextBoolean()); + mLayout.addView(button); + } + + private void createSwitch() { + Switch button = new Switch(this); + button.setChecked(mRandom.nextBoolean()); + mLayout.addView(button); + } + + private void createChronometer() { + Chronometer chronometer = new Chronometer(this); + chronometer.setBase(mRandom.nextLong()); + mLayout.addView(chronometer); + chronometer.start(); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + public boolean onPreDraw() { + // Interpolate indicator color + int background = 0xff000000; + for (int i = 0; i < 3; ++i) { + int shift = 8 * i; + int colorB = (BACKGROUND_COLOR >> shift) & 0xff; + int colorI = (INDICATOR_COLOR >> shift) & 0xff; + int color = (int)((float)colorB * (1.0f - mIndicatorState) + + (float)colorI * mIndicatorState); + if (color > 255) { + color = 255; + } + background |= (color << shift); + } + + mIndicator.setBackgroundColor(background); + mIndicatorState += (3 / 60.0f); // around 3 times per second + mIndicatorState = mIndicatorState - (int)mIndicatorState; + + mLayout.postInvalidate(); + return true; + } +}
\ No newline at end of file diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java b/tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java new file mode 100644 index 000000000000..9a2b9ccb4f90 --- /dev/null +++ b/tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java @@ -0,0 +1,111 @@ +/* + * 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.windowanimationjank; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +/** + * Custom layout that place all elements in flows with and automatically wraps them. + */ +public class FlowLayout extends ViewGroup { + private int mLineHeight; + + public FlowLayout(Context context) { + super(context); + } + + public FlowLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int width = + MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() -getPaddingRight(); + int height = + MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom(); + final int count = getChildCount(); + + int x = getPaddingLeft(); + int y = getPaddingTop(); + int lineHeight = 0; + + int childHeightMeasureSpec; + if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { + childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); + } else { + childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + } + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), + childHeightMeasureSpec); + final int childWidth = child.getMeasuredWidth(); + lineHeight = Math.max(lineHeight, child.getMeasuredHeight()); + + if (x + childWidth > width) { + x = getPaddingLeft(); + y += lineHeight; + } + + x += childWidth; + } + } + mLineHeight = lineHeight; + + if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) { + height = y + lineHeight; + } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { + if (y + lineHeight < height) { + height = y + lineHeight; + } + } + setMeasuredDimension(width, height); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + if (p instanceof LayoutParams) { + return true; + } + return false; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int count = getChildCount(); + final int width = r - l; + int x = getPaddingLeft(); + int y = getPaddingTop(); + + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final int childWidth = child.getMeasuredWidth(); + final int childHeight = child.getMeasuredHeight(); + if (x + childWidth > width) { + x = getPaddingLeft(); + y += mLineHeight; + } + child.layout(x, y, x + childWidth, y + childHeight); + x += childWidth; + } + } + } +} diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java b/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java new file mode 100644 index 000000000000..1fb502a09874 --- /dev/null +++ b/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java @@ -0,0 +1,53 @@ +/* + * 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.windowanimationjank; + +import android.os.Bundle; +import android.support.test.jank.JankTest; +import android.support.test.jank.GfxMonitor; + +/** + * Detect janks during screen rotation for full-screen activity. Periodically change + * orientation from left to right and track ElementLayoutActivity rendering performance + * via GfxMonitor. + */ +public class FullscreenRotationTest extends WindowAnimationJankTestBase { + private final static int STEP_CNT = 3; + + @Override + public void beforeTest() throws Exception { + getUiDevice().setOrientationLeft(); + Utils.startElementLayout(getInstrumentation(), 100); + super.beforeTest(); + } + + @Override + public void afterTest(Bundle metrics) { + Utils.rotateDevice(getInstrumentation(), Utils.ROTATION_MODE_NATURAL); + super.afterTest(metrics); + } + + @JankTest(expectedFrames=100, defaultIterationCount=2) + @GfxMonitor(processName=Utils.PACKAGE) + public void testRotation() throws Exception { + for (int i = 0; i < STEP_CNT; ++i) { + Utils.rotateDevice(getInstrumentation(), + Utils.getDeviceRotation(getInstrumentation()) == Utils.ROTATION_MODE_LEFT ? + Utils.ROTATION_MODE_RIGHT : Utils.ROTATION_MODE_LEFT); + } + } +} diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java b/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java new file mode 100644 index 000000000000..25314644ca7e --- /dev/null +++ b/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java @@ -0,0 +1,118 @@ +/* + * 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.windowanimationjank; + +import android.app.Instrumentation; +import android.app.UiAutomation; +import android.content.ComponentName; +import android.content.Intent; +import android.os.SystemClock; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.BySelector; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; + +/** + * Set of helpers to manipulate test activities. + */ +public class Utils { + protected final static String PACKAGE = "android.windowanimationjank"; + protected final static String ELEMENT_LAYOUT_ACTIVITY = "ElementLayoutActivity"; + protected final static String ELEMENT_LAYOUT_CLASS = PACKAGE + "." + ELEMENT_LAYOUT_ACTIVITY; + protected final static long WAIT_FOR_ACTIVITY_TIMEOUT = 10000; + private static final BySelector ROOT_ELEMENT_LAYOUT = By.res(PACKAGE, "root_flow_layout"); + + private final static long ROTATION_ANIMATION_TIME_FULL_SCREEN_MS = 1000; + + protected final static int ROTATION_MODE_NATURAL = 0; + protected final static int ROTATION_MODE_LEFT = 1; + protected final static int ROTATION_MODE_RIGHT = 2; + + private static UiObject2 waitForActivity(Instrumentation instrumentation, BySelector selector) { + UiDevice device = UiDevice.getInstance(instrumentation); + UiObject2 window = device.wait(Until.findObject(selector), WAIT_FOR_ACTIVITY_TIMEOUT); + if (window == null) { + throw new RuntimeException(selector.toString() + " has not been started."); + } + + // Get root object. + while (window.getParent() != null) { + window = window.getParent(); + } + return window; + } + + public static UiObject2 waitForElementLayout(Instrumentation instrumentation) { + return waitForActivity(instrumentation, ROOT_ELEMENT_LAYOUT); + } + + /** + * Start and return activity with requested number of random elements. + */ + public static UiObject2 startElementLayout(Instrumentation instrumentation, int numElements) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setComponent(new ComponentName(PACKAGE, ELEMENT_LAYOUT_CLASS)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(ElementLayoutActivity.NUM_ELEMENTS_KEY, numElements); + instrumentation.getTargetContext().startActivity(intent); + return waitForElementLayout(instrumentation); + } + + public static int getDeviceRotation(Instrumentation instrumentation) { + try { + UiDevice device = UiDevice.getInstance(instrumentation); + switch (device.getDisplayRotation()) { + case UiAutomation.ROTATION_FREEZE_90: + return ROTATION_MODE_LEFT; + case UiAutomation.ROTATION_FREEZE_270: + return ROTATION_MODE_RIGHT; + case UiAutomation.ROTATION_FREEZE_0: + case UiAutomation.ROTATION_FREEZE_180: + return ROTATION_MODE_NATURAL; + } + } catch(Exception e) { + throw new RuntimeException(); + } + throw new RuntimeException("Unsupported device rotation."); + } + + public static void rotateDevice(Instrumentation instrumentation, int rotationMode) { + try { + UiDevice device = UiDevice.getInstance(instrumentation); + long startTime = System.currentTimeMillis(); + switch (rotationMode) { + case ROTATION_MODE_NATURAL: + device.setOrientationNatural(); + break; + case ROTATION_MODE_LEFT: + device.setOrientationLeft(); + break; + case ROTATION_MODE_RIGHT: + device.setOrientationRight(); + break; + default: + throw new RuntimeException("Unsupported rotation mode: " + rotationMode); + } + + long toSleep = ROTATION_ANIMATION_TIME_FULL_SCREEN_MS - + (System.currentTimeMillis() - startTime); + if (toSleep > 0) { + SystemClock.sleep(toSleep); + } + } catch(Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java new file mode 100644 index 000000000000..bf739fa8da07 --- /dev/null +++ b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java @@ -0,0 +1,56 @@ +/* + * 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.windowanimationjank; + +import java.io.IOException; +import java.util.StringTokenizer; + +import android.support.test.jank.JankTestBase; +import android.support.test.uiautomator.UiDevice; + +/** + * This adds additional system level jank monitor and its result is merged with primary monitor + * used in test. + */ +public abstract class WindowAnimationJankTestBase extends JankTestBase { + private static final String TAG = "WindowAnimationJankTestBase"; + + protected WindowAnimationJankTestBase() { + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // fix device orientation + getUiDevice().setOrientationNatural(); + + // Start from the home screen + getUiDevice().pressHome(); + getUiDevice().waitForIdle(); + } + + @Override + protected void tearDown() throws Exception { + getUiDevice().unfreezeRotation(); + super.tearDown(); + } + + protected UiDevice getUiDevice() { + return UiDevice.getInstance(getInstrumentation()); + } +} diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java index b9e7500598d1..a390b0cab321 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -175,16 +175,6 @@ public class WindowManagerPermissionTests extends TestCase { } try { - mWm.setAppWillBeHidden(null); - fail("IWindowManager.setAppWillBeHidden did not throw SecurityException as" - + " expected"); - } catch (SecurityException e) { - // expected - } catch (RemoteException e) { - fail("Unexpected remote exception"); - } - - try { mWm.setAppVisibility(null, false); fail("IWindowManager.setAppVisibility did not throw SecurityException as" + " expected"); diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java index 163fbcb7f900..f4b1f2cd363f 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java @@ -48,9 +48,6 @@ import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Iterator; -/** - * - */ public final class BridgeResources extends Resources { private BridgeContext mContext; @@ -278,7 +275,7 @@ public final class BridgeResources extends Resources { * always Strings. The ideal signature for the method should be <T super String>, but java * generics don't support it. */ - private <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) { + <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) { int i = 0; for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) { @SuppressWarnings("unchecked") @@ -404,7 +401,7 @@ public final class BridgeResources extends Resources { if (xml.isFile()) { // we need to create a pull parser around the layout XML file, and then // give that to our XmlBlockParser - parser = ParserFactory.create(xml); + parser = ParserFactory.create(xml, true); } } diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java index 6a6109047573..31dd3d943769 100644 --- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java @@ -16,6 +16,7 @@ package android.content.res; +import com.android.ide.common.rendering.api.ArrayResourceValue; import com.android.ide.common.rendering.api.AttrResourceValue; import com.android.ide.common.rendering.api.LayoutLog; import com.android.ide.common.rendering.api.RenderResources; @@ -33,6 +34,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.annotation.Nullable; +import android.content.res.Resources.NotFoundException; import android.content.res.Resources.Theme; import android.graphics.drawable.Drawable; import android.util.DisplayMetrics; @@ -740,12 +742,20 @@ public final class BridgeTypedArray extends TypedArray { */ @Override public CharSequence[] getTextArray(int index) { - String value = getString(index); - if (value != null) { - return new CharSequence[] { value }; + if (!hasValue(index)) { + return null; } - - return null; + ResourceValue resVal = mResourceData[index]; + if (resVal instanceof ArrayResourceValue) { + ArrayResourceValue array = (ArrayResourceValue) resVal; + int count = array.getElementCount(); + return count >= 0 ? mBridgeResources.fillValues(array, new CharSequence[count]) : null; + } + int id = getResourceId(index, 0); + String resIdMessage = id > 0 ? " (resource id 0x" + Integer.toHexString(id) + ')' : ""; + throw new NotFoundException( + String.format("%1$s in %2$s%3$s is not a valid array resource.", + resVal.getValue(), mNames[index], resIdMessage)); } @Override diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java index 857e6d03283e..c7b24bcb352d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java @@ -178,7 +178,9 @@ public class FontFamily_Delegate { desiredStyle.mIsItalic = isItalic; FontInfo bestFont = null; int bestMatch = Integer.MAX_VALUE; - for (FontInfo font : mFonts) { + //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation) + for (int i = 0, n = mFonts.size(); i < n; i++) { + FontInfo font = mFonts.get(i); int match = computeMatch(font, desiredStyle); if (match < bestMatch) { bestMatch = match; @@ -415,7 +417,9 @@ public class FontFamily_Delegate { boolean isItalic = fontInfo.mIsItalic; // The list is usually just two fonts big. So iterating over all isn't as bad as it looks. // It's biggest for roboto where the size is 12. - for (FontInfo font : mFonts) { + //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation) + for (int i = 0, n = mFonts.size(); i < n; i++) { + FontInfo font = mFonts.get(i); if (font.mWeight == weight && font.mIsItalic == isItalic) { return false; } diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index 65b65ec759d0..a545283ea0ca 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -480,8 +480,10 @@ public class Paint_Delegate { return; } - delegate.mTextSize = textSize; - delegate.updateFontObject(); + if (delegate.mTextSize != textSize) { + delegate.mTextSize = textSize; + delegate.updateFontObject(); + } } @LayoutlibDelegate @@ -503,8 +505,10 @@ public class Paint_Delegate { return; } - delegate.mTextScaleX = scaleX; - delegate.updateFontObject(); + if (delegate.mTextScaleX != scaleX) { + delegate.mTextScaleX = scaleX; + delegate.updateFontObject(); + } } @LayoutlibDelegate @@ -526,8 +530,10 @@ public class Paint_Delegate { return; } - delegate.mTextSkewX = skewX; - delegate.updateFontObject(); + if (delegate.mTextSkewX != skewX) { + delegate.mTextSkewX = skewX; + delegate.updateFontObject(); + } } @LayoutlibDelegate @@ -897,9 +903,12 @@ public class Paint_Delegate { return 0; } - delegate.mTypeface = Typeface_Delegate.getDelegate(typeface); - delegate.mNativeTypeface = typeface; - delegate.updateFontObject(); + Typeface_Delegate typefaceDelegate = Typeface_Delegate.getDelegate(typeface); + if (delegate.mTypeface != typefaceDelegate || delegate.mNativeTypeface != typeface) { + delegate.mTypeface = Typeface_Delegate.getDelegate(typeface); + delegate.mNativeTypeface = typeface; + delegate.updateFontObject(); + } return typeface; } @@ -1214,13 +1223,31 @@ public class Paint_Delegate { mCap = paint.mCap; mJoin = paint.mJoin; mTextAlign = paint.mTextAlign; - mTypeface = paint.mTypeface; - mNativeTypeface = paint.mNativeTypeface; + + boolean needsFontUpdate = false; + if (mTypeface != paint.mTypeface || mNativeTypeface != paint.mNativeTypeface) { + mTypeface = paint.mTypeface; + mNativeTypeface = paint.mNativeTypeface; + needsFontUpdate = true; + } + + if (mTextSize != paint.mTextSize) { + mTextSize = paint.mTextSize; + needsFontUpdate = true; + } + + if (mTextScaleX != paint.mTextScaleX) { + mTextScaleX = paint.mTextScaleX; + needsFontUpdate = true; + } + + if (mTextSkewX != paint.mTextSkewX) { + mTextSkewX = paint.mTextSkewX; + needsFontUpdate = true; + } + mStrokeWidth = paint.mStrokeWidth; mStrokeMiter = paint.mStrokeMiter; - mTextSize = paint.mTextSize; - mTextScaleX = paint.mTextScaleX; - mTextSkewX = paint.mTextSkewX; mXfermode = paint.mXfermode; mColorFilter = paint.mColorFilter; mShader = paint.mShader; @@ -1228,7 +1255,10 @@ public class Paint_Delegate { mMaskFilter = paint.mMaskFilter; mRasterizer = paint.mRasterizer; mHintingMode = paint.mHintingMode; - updateFontObject(); + + if (needsFontUpdate) { + updateFontObject(); + } } private void reset() { @@ -1264,10 +1294,18 @@ public class Paint_Delegate { // Get the fonts from the TypeFace object. List<Font> fonts = mTypeface.getFonts(mFontVariant); + if (fonts.isEmpty()) { + mFonts = Collections.emptyList(); + return; + } + // create new font objects as well as FontMetrics, based on the current text size // and skew info. - ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size()); - for (Font font : fonts) { + int nFonts = fonts.size(); + ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(nFonts); + //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation) + for (int i = 0; i < nFonts; i++) { + Font font = fonts.get(i); if (font == null) { // If the font is null, add null to infoList. When rendering the text, if this // null is reached, a warning will be logged. diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java index f1726ebae4cb..5db1bde5f3f0 100644 --- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java +++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java @@ -206,7 +206,7 @@ public final class BridgeInflater extends LayoutInflater { File f = new File(value.getValue()); if (f.isFile()) { try { - XmlPullParser parser = ParserFactory.create(f); + XmlPullParser parser = ParserFactory.create(f, true); BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser( parser, bridgeContext, value.isFramework()); diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 778d1a5e51ac..0da6bb62006c 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -338,11 +338,6 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void setAppWillBeHidden(IBinder arg0) throws RemoteException { - // TODO Auto-generated method stub - } - - @Override public void setEventDispatching(boolean arg0) throws RemoteException { // TODO Auto-generated method stub } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 689e3597720b..b2dc29a90fb1 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -436,7 +436,7 @@ public final class BridgeContext extends Context { // we need to create a pull parser around the layout XML file, and then // give that to our XmlBlockParser try { - XmlPullParser parser = ParserFactory.create(xml); + XmlPullParser parser = ParserFactory.create(xml, true); // set the resource ref to have correct view cookies mBridgeInflater.setResourceReference(resource); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java index f04654eded0f..e3a19e76a3ef 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java @@ -65,6 +65,12 @@ public class BridgePackageManager extends PackageManager { } @Override + public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) + throws NameNotFoundException { + return null; + } + + @Override public String[] currentToCanonicalPackageNames(String[] names) { return new String[0]; } @@ -499,6 +505,11 @@ public class BridgePackageManager extends PackageManager { } @Override + public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,int flags, + String installerPackageName, int userId) { + } + + @Override public void installPackageWithVerification(Uri packageURI, PackageInstallObserver observer, int flags, String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) { @@ -516,6 +527,12 @@ public class BridgePackageManager extends PackageManager { } @Override + public int installExistingPackageAsUser(String packageName, int userId) + throws NameNotFoundException { + return 0; + } + + @Override public void verifyPendingInstall(int id, int verificationCode) { } @@ -568,6 +585,11 @@ public class BridgePackageManager extends PackageManager { } @Override + public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags, + int userId) { + } + + @Override public String getInstallerPackageName(String packageName) { return null; } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java new file mode 100644 index 000000000000..71e7fd2c5eea --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java @@ -0,0 +1,377 @@ +/* + * 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.layoutlib.bridge.impl; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.annotation.Nullable; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A wrapper around XmlPullParser that can peek forward to inspect if the file is a data-binding + * layout and some parts need to be stripped. + */ +public class LayoutParserWrapper implements XmlPullParser { + + // Data binding constants. + private static final String TAG_LAYOUT = "layout"; + private static final String TAG_DATA = "data"; + private static final String DEFAULT = "default="; + + private final XmlPullParser mDelegate; + + // Storage for peeked values. + private boolean mPeeked; + private int mEventType; + private int mDepth; + private int mNext; + private List<Attribute> mAttributes; + private String mText; + private String mName; + + // Used to end the document before the actual parser ends. + private int mFinalDepth = -1; + private boolean mEndNow; + + public LayoutParserWrapper(XmlPullParser delegate) { + mDelegate = delegate; + } + + public LayoutParserWrapper peekTillLayoutStart() throws IOException, XmlPullParserException { + final int STATE_LAYOUT_NOT_STARTED = 0; // <layout> tag not encountered yet. + final int STATE_ROOT_NOT_STARTED = 1; // the main view root not found yet. + final int STATE_INSIDE_DATA = 2; // START_TAG for <data> found, but not END_TAG. + + int state = STATE_LAYOUT_NOT_STARTED; + int dataDepth = -1; // depth of the <data> tag. Should be two. + while (true) { + int peekNext = peekNext(); + switch (peekNext) { + case START_TAG: + if (state == STATE_LAYOUT_NOT_STARTED) { + if (mName.equals(TAG_LAYOUT)) { + state = STATE_ROOT_NOT_STARTED; + } else { + return this; // no layout tag in the file. + } + } else if (state == STATE_ROOT_NOT_STARTED) { + if (mName.equals(TAG_DATA)) { + state = STATE_INSIDE_DATA; + dataDepth = mDepth; + } else { + mFinalDepth = mDepth; + return this; + } + } + break; + case END_TAG: + if (state == STATE_INSIDE_DATA) { + if (mDepth <= dataDepth) { + state = STATE_ROOT_NOT_STARTED; + } + } + break; + case END_DOCUMENT: + // No layout start found. + return this; + } + // consume the peeked tag. + next(); + } + } + + private int peekNext() throws IOException, XmlPullParserException { + if (mPeeked) { + return mNext; + } + mEventType = mDelegate.getEventType(); + mNext = mDelegate.next(); + if (mEventType == START_TAG) { + int count = mDelegate.getAttributeCount(); + mAttributes = count > 0 ? new ArrayList<Attribute>(count) : + Collections.<Attribute>emptyList(); + for (int i = 0; i < count; i++) { + mAttributes.add(new Attribute(mDelegate.getAttributeNamespace(i), + mDelegate.getAttributeName(i), mDelegate.getAttributeValue(i))); + } + } + mDepth = mDelegate.getDepth(); + mText = mDelegate.getText(); + mName = mDelegate.getName(); + mPeeked = true; + return mNext; + } + + private void reset() { + mAttributes = null; + mText = null; + mName = null; + mPeeked = false; + } + + @Override + public int next() throws XmlPullParserException, IOException { + int returnValue; + int depth; + if (mPeeked) { + returnValue = mNext; + depth = mDepth; + reset(); + } else if (mEndNow) { + return END_DOCUMENT; + } else { + returnValue = mDelegate.next(); + depth = getDepth(); + } + if (returnValue == END_TAG && depth <= mFinalDepth) { + mEndNow = true; + } + return returnValue; + } + + @Override + public int getEventType() throws XmlPullParserException { + return mPeeked ? mEventType : mDelegate.getEventType(); + } + + @Override + public int getDepth() { + return mPeeked ? mDepth : mDelegate.getDepth(); + } + + @Override + public String getName() { + return mPeeked ? mName : mDelegate.getName(); + } + + @Override + public String getText() { + return mPeeked ? mText : mDelegate.getText(); + } + + @Override + public String getAttributeValue(@Nullable String namespace, String name) { + String returnValue = null; + if (mPeeked) { + if (mAttributes == null) { + if (mEventType != START_TAG) { + throw new IndexOutOfBoundsException("getAttributeValue() called when not at START_TAG."); + } else { + return null; + } + } else { + for (Attribute attribute : mAttributes) { + //noinspection StringEquality for nullness check. + if (attribute.name.equals(name) && (attribute.namespace == namespace || + attribute.namespace != null && attribute.namespace.equals(namespace))) { + returnValue = attribute.value; + break; + } + } + } + } else { + returnValue = mDelegate.getAttributeValue(namespace, name); + } + // Check if the value is bound via data-binding, if yes get the default value. + if (returnValue != null && mFinalDepth >= 0 && returnValue.startsWith("@{")) { + // TODO: Improve the detection of default keyword. + int i = returnValue.lastIndexOf(DEFAULT); + return i > 0 ? returnValue.substring(i + DEFAULT.length(), returnValue.length() - 1) + : null; + } + return returnValue; + } + + private static class Attribute { + @Nullable + public final String namespace; + public final String name; + public final String value; + + public Attribute(@Nullable String namespace, String name, String value) { + this.namespace = namespace; + this.name = name; + this.value = value; + } + } + + // Not affected by peeking. + + @Override + public void setFeature(String s, boolean b) throws XmlPullParserException { + mDelegate.setFeature(s, b); + } + + @Override + public void setProperty(String s, Object o) throws XmlPullParserException { + mDelegate.setProperty(s, o); + } + + @Override + public void setInput(InputStream inputStream, String s) throws XmlPullParserException { + mDelegate.setInput(inputStream, s); + } + + @Override + public void setInput(Reader reader) throws XmlPullParserException { + mDelegate.setInput(reader); + } + + @Override + public String getInputEncoding() { + return mDelegate.getInputEncoding(); + } + + @Override + public String getNamespace(String s) { + return mDelegate.getNamespace(s); + } + + @Override + public String getPositionDescription() { + return mDelegate.getPositionDescription(); + } + + @Override + public int getLineNumber() { + return mDelegate.getLineNumber(); + } + + @Override + public String getNamespace() { + return mDelegate.getNamespace(); + } + + @Override + public int getColumnNumber() { + return mDelegate.getColumnNumber(); + } + + // -- We don't care much about the methods that follow. + + @Override + public void require(int i, String s, String s1) throws XmlPullParserException, IOException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public boolean getFeature(String s) { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public void defineEntityReplacementText(String s, String s1) throws XmlPullParserException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public Object getProperty(String s) { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public int nextToken() throws XmlPullParserException, IOException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public int getNamespaceCount(int i) throws XmlPullParserException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public String getNamespacePrefix(int i) throws XmlPullParserException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public String getNamespaceUri(int i) throws XmlPullParserException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public boolean isWhitespace() throws XmlPullParserException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public char[] getTextCharacters(int[] ints) { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public String getPrefix() { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public boolean isEmptyElementTag() throws XmlPullParserException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public int getAttributeCount() { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public String getAttributeNamespace(int i) { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public String getAttributeName(int i) { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public String getAttributePrefix(int i) { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public String getAttributeType(int i) { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public boolean isAttributeDefault(int i) { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public String getAttributeValue(int i) { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public String nextText() throws XmlPullParserException, IOException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } + + @Override + public int nextTag() throws XmlPullParserException, IOException { + throw new UnsupportedOperationException("Only few parser methods are supported."); + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java index 6e67f593aa53..e273b2cd75cc 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java @@ -53,24 +53,35 @@ public class ParserFactory { @NonNull public static XmlPullParser create(@NonNull File f) throws XmlPullParserException, FileNotFoundException { - InputStream stream = new FileInputStream(f); - return create(stream, f.getName(), f.length()); + return create(f, false); } + public static XmlPullParser create(@NonNull File f, boolean isLayout) + throws XmlPullParserException, FileNotFoundException { + InputStream stream = new FileInputStream(f); + return create(stream, f.getName(), f.length(), isLayout); + } @NonNull public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name) throws XmlPullParserException { - return create(stream, name, -1); + return create(stream, name, -1, false); } @NonNull private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name, - long size) throws XmlPullParserException { + long size, boolean isLayout) throws XmlPullParserException { XmlPullParser parser = instantiateParser(name); stream = readAndClose(stream, name, size); parser.setInput(stream, ENCODING); + if (isLayout) { + try { + return new LayoutParserWrapper(parser).peekTillLayoutStart(); + } catch (IOException e) { + throw new XmlPullParserException(null, parser, e); + } + } return parser; } diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java new file mode 100644 index 000000000000..2c338622301b --- /dev/null +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java @@ -0,0 +1,183 @@ +/* + * 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.layoutlib.bridge.impl; + +import org.junit.Test; +import org.kxml2.io.KXmlParser; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.StringReader; + +import static com.android.SdkConstants.NS_RESOURCES; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.END_TAG; +import static org.xmlpull.v1.XmlPullParser.START_TAG; + + +public class LayoutParserWrapperTest { + @Test + @SuppressWarnings("StatementWithEmptyBody") // some for loops need to be empty statements. + public void testDataBindingLayout() throws Exception { + LayoutParserWrapper parser = getParserFromString(sDataBindingLayout); + parser.peekTillLayoutStart(); + assertEquals("Expected START_TAG", START_TAG, parser.next()); + assertEquals("RelativeLayout", parser.getName()); + for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT; + next = parser.next()); + assertEquals("Expected START_TAG", START_TAG, parser.getEventType()); + assertEquals("TextView", parser.getName()); + assertEquals("layout_width incorrect for first text view.", "wrap_content", + parser.getAttributeValue(NS_RESOURCES, "layout_width")); + // Ensure that data-binding part is stripped. + assertEquals("Bound attribute android:text incorrect", "World", + parser.getAttributeValue(NS_RESOURCES, "text")); + assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first", + parser.getAttributeValue(NS_RESOURCES, "id")); + for (int next = parser.next(); + (next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT; + next = parser.next()); + assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType()); + assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next()); + } + + @Test + @SuppressWarnings("StatementWithEmptyBody") + public void testNonDataBindingLayout() throws Exception { + LayoutParserWrapper parser = getParserFromString(sNonDataBindingLayout); + parser.peekTillLayoutStart(); + assertEquals("Expected START_TAG", START_TAG, parser.next()); + assertEquals("RelativeLayout", parser.getName()); + for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT; + next = parser.next()); + assertEquals("Expected START_TAG", START_TAG, parser.getEventType()); + assertEquals("TextView", parser.getName()); + assertEquals("layout_width incorrect for first text view.", "wrap_content", + parser.getAttributeValue(NS_RESOURCES, "layout_width")); + // Ensure that value isn't modified. + assertEquals("Bound attribute android:text incorrect", "@{user.firstName,default=World}", + parser.getAttributeValue(NS_RESOURCES, "text")); + assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first", + parser.getAttributeValue(NS_RESOURCES, "id")); + for (int next = parser.next(); + (next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT; + next = parser.next()); + assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType()); + assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next()); + } + + private static LayoutParserWrapper getParserFromString(String layoutContent) throws + XmlPullParserException { + XmlPullParser parser = new KXmlParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + parser.setInput(new StringReader(layoutContent)); + return new LayoutParserWrapper(parser); + } + + private static final String sDataBindingLayout = + //language=XML + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + "<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" + + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + + " tools:context=\".MainActivity\"\n" + + " tools:showIn=\"@layout/activity_main\">\n" + + "\n" + + " <data>\n" + + "\n" + + " <variable\n" + + " name=\"user\"\n" + + " type=\"com.example.User\" />\n" + + " <variable\n" + + " name=\"activity\"\n" + + " type=\"com.example.MainActivity\" />\n" + + " </data>\n" + + "\n" + + " <RelativeLayout\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" + + " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" + + " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" + + " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" + + " app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" + + " >\n" + + "\n" + + " <TextView\n" + + " android:id=\"@+id/first\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_alignParentStart=\"true\"\n" + + " android:layout_alignParentLeft=\"true\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:text=\"@{user.firstName,default=World}\" />\n" + + "\n" + + " <TextView\n" + + " android:id=\"@+id/last\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_toEndOf=\"@id/first\"\n" + + " android:layout_toRightOf=\"@id/first\"\n" + + " android:text=\"@{user.lastName,default=Hello}\" />\n" + + "\n" + + " <Button\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_below=\"@id/last\"\n" + + " android:text=\"Submit\"\n" + + " android:onClick=\"@{activity.onClick}\"/>\n" + + " </RelativeLayout>\n" + + "</layout>"; + + private static final String sNonDataBindingLayout = + //language=XML + "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + + " xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" + + " android:layout_width=\"match_parent\"\n" + + " android:layout_height=\"match_parent\"\n" + + " android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" + + " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" + + " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" + + " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" + + " app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" + + ">\n" + + "\n" + + " <TextView\n" + + " android:id=\"@+id/first\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_alignParentStart=\"true\"\n" + + " android:layout_alignParentLeft=\"true\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:text=\"@{user.firstName,default=World}\" />\n" + + "\n" + + " <TextView\n" + + " android:id=\"@+id/last\"\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_toEndOf=\"@id/first\"\n" + + " android:layout_toRightOf=\"@id/first\"\n" + + " android:text=\"@{user.lastName,default=Hello}\" />\n" + + "\n" + + " <Button\n" + + " android:layout_width=\"wrap_content\"\n" + + " android:layout_height=\"wrap_content\"\n" + + " android:layout_below=\"@id/last\"\n" + + " android:text=\"Submit\"\n" + + " android:onClick=\"@{activity.onClick}\"/>\n" + + "</RelativeLayout>"; +} diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 0d95b38feb46..23be8e076174 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -23,6 +23,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.ScanSettings; import android.net.wifi.WifiChannel; import android.net.wifi.ScanResult; +import android.net.wifi.ScanInfo; import android.net.wifi.WifiConnectionStatistics; import android.net.wifi.WifiActivityEnergyInfo; import android.net.Network; @@ -70,6 +71,10 @@ interface IWifiManager void disconnect(); + List<ScanInfo> getScanInfos(String callingPackage); + + void setOsuSelection(int osuID); + void reconnect(); void reassociate(); diff --git a/wifi/java/android/net/wifi/ScanInfo.aidl b/wifi/java/android/net/wifi/ScanInfo.aidl new file mode 100644 index 000000000000..18ae5088146f --- /dev/null +++ b/wifi/java/android/net/wifi/ScanInfo.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.net.wifi; + +parcelable ScanInfo; diff --git a/wifi/java/android/net/wifi/ScanInfo.java b/wifi/java/android/net/wifi/ScanInfo.java new file mode 100644 index 000000000000..39186fa7a38a --- /dev/null +++ b/wifi/java/android/net/wifi/ScanInfo.java @@ -0,0 +1,189 @@ +package android.net.wifi; + +import android.os.Parcel; +import android.os.Parcelable; + +public class ScanInfo implements Parcelable { + private final ScanResult mScanResult; + + private final long mBSSID; // The BSSID of the best AP with an SSID matching the OSU + private final int mRSSI; // RSSI of the AP with BSSID + private final String mSSID; // The SSID to connect to for an OSU connection. + private final String mName; + private final String mServiceDescription; + private final String mIconType; + private final byte[] mIconData; + private final int mOSUIdentity; + + public ScanInfo(ScanResult scanResult) { + mScanResult = scanResult; + + mBSSID = -1; + mRSSI = -1; + mSSID = null; + mName = null; + mServiceDescription = null; + mIconType = null; + mIconData = null; + mOSUIdentity = -1; + } + + public ScanInfo(long BSSID, int rssi, String SSID, String name, String serviceDescription, + String iconType, byte[] iconData, int OSUIdentity) { + mBSSID = BSSID; + mRSSI = rssi; + mSSID = SSID; + mName = name; + mServiceDescription = serviceDescription; + mIconType = iconType; + mIconData = iconData; + mOSUIdentity = OSUIdentity; + + mScanResult = null; + } + + /** + * Get the scan result of this ScanInfo. + * @return The ScanResult, if this ScanInfo contains a one. If the ScanInfo contains + * OSU information getScanResult will return null. + */ + public ScanResult getScanResult() { + return mScanResult; + } + + /** + * OSU only: The BSSID of the AP who advertises the OSU SSID. This value is not guaranteed to + * be correct; In the somewhat unlikely case that multiple APs advertise OSU SSIDs that matches + * an OSU information element returned through ANQP and one of those is not related to an OSU + * there is a (slight) risk that the BSSID is for a "spoof" OSU. + * The matching algorithm that produces the ScanInfo objects makes a best effort to get the + * matching right though and since it is (a) fair to assume that the OSU SSID resides on the + * same AP as the one advertising the OSU information, and (b) BSSIDs for multi-SSID APs are + * typically adjacent to each other, matching will prefer the BSSID closest to the advertising + * APs BSSID if multiple SSIDs match. + * @return The BSSID. + */ + public long getBssid() { + return mBSSID; + } + + /** + * OSU only. + * @return The signal level of the AP associated with the BSSID from getBSSID. + */ + public int getRssi() { + return mRSSI; + } + + /** + * OSU only. + * @return The SSID of the AP to which to associate to establish an OSU connection. + */ + public String getSsid() { + return mSSID; + } + + /** + * OSU only. + * @return The name of the Service Provider of the OSU. + */ + public String getName() { + return mName; + } + + /** + * OSU only. + * @return The service description of the OSU. + */ + public String getServiceDescription() { + return mServiceDescription; + } + + /** + * OSU only. + * Get the type of icon that icon data represents, e.g. JPG, PNG etc. This field is formatted + * using standard MIME encodings per RFC-4288 and IANA MIME media types. + * @return The icon type in icon data. + */ + public String getIconType() { + return mIconType; + } + + /** + * OSU only. + * @return The binary data of the icon. + */ + public byte[] getIconData() { + return mIconData; + } + + /** + * OSU only. + * @return a unique identity for the OSU. This value is generated by the framework and should + * be used to uniquely identify a specific OSU. Please note that values may be reused after + * a very long time-span (in any normal scenario, likely years) and implementations should make + * sure to not rely on any long term persisted values. + */ + public int getOsuIdentity() { + return mOSUIdentity; + } + + private static final int ScanResultMarker = 0; + private static final int OSUMarker = 1; + + @Override + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<ScanInfo> CREATOR = + new Creator<ScanInfo>() { + @Override + public ScanInfo createFromParcel(Parcel source) { + int marker = source.readInt(); + if (marker == ScanResultMarker) { + return new ScanInfo(ScanResult.CREATOR.createFromParcel(source)); + } + else if (marker == OSUMarker) { + return new ScanInfo( + source.readLong(), + source.readInt(), + source.readString(), + source.readString(), + source.readString(), + source.readString(), + source.createByteArray(), + source.readInt() + ); + } + else { + throw new RuntimeException("Bad ScanInfo data"); + } + } + + @Override + public ScanInfo[] newArray(int size) { + return new ScanInfo[0]; + } + }; + + @Override + public void writeToParcel(Parcel dest, int flags) { + if (mScanResult != null) { + dest.writeInt(ScanResultMarker); + mScanResult.writeToParcel(dest, flags); + return; + } + + dest.writeInt(OSUMarker); + dest.writeLong(mBSSID); + dest.writeInt(mRSSI); + dest.writeString(mSSID); + dest.writeString(mName); + dest.writeString(mServiceDescription); + dest.writeString(mIconType); + dest.writeByteArray(mIconData); + dest.writeInt(mOSUIdentity); + } +} diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index cf88df42f8d3..ff8d6d4d09aa 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1315,6 +1315,30 @@ public class WifiManager { } /** + * An augmented version of getScanResults that returns ScanResults as well as OSU information + * wrapped in ScanInfo objects. + * @return + */ + public List<ScanInfo> getScanInfos() { + try { + return mService.getScanInfos(mContext.getOpPackageName()); + } catch (RemoteException e) { + return null; + } + } + + /** + * Notify the OSU framework about the currently selected OSU. + * @param osuID The OSU ID from ScanInfo.getOsuIdentity() + */ + public void setOsuSelection(int osuID) { + try { + mService.setOsuSelection(osuID); + } catch (RemoteException e) { + } + } + + /** * Check if scanning is always available. * * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results |