Merge "Input devices configure on per-display basis (2/2)"
diff --git a/api/current.txt b/api/current.txt
index afd09ad..6a2c842 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5811,6 +5811,7 @@
method public final void setInterruptionFilter(int);
method public void setNotificationDelegate(@NonNull String);
method public void setNotificationPolicy(@NonNull android.app.NotificationManager.Policy);
+ method public boolean shouldHideSilentStatusBarIcons();
method public boolean updateAutomaticZenRule(String, android.app.AutomaticZenRule);
field public static final String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
field public static final String ACTION_AUTOMATIC_ZEN_RULE = "android.app.action.AUTOMATIC_ZEN_RULE";
@@ -36527,7 +36528,7 @@
field public static final String ACCOUNT_TYPE_LOCAL = "LOCAL";
field public static final String ACTION_EVENT_REMINDER = "android.intent.action.EVENT_REMINDER";
field public static final String ACTION_HANDLE_CUSTOM_EVENT = "android.provider.calendar.action.HANDLE_CUSTOM_EVENT";
- field public static final String ACTION_VIEW_WORK_CALENDAR_EVENT = "android.provider.calendar.action.VIEW_WORK_CALENDAR_EVENT";
+ field public static final String ACTION_VIEW_MANAGED_PROFILE_CALENDAR_EVENT = "android.provider.calendar.action.VIEW_MANAGED_PROFILE_CALENDAR_EVENT";
field public static final String AUTHORITY = "com.android.calendar";
field public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
field public static final android.net.Uri CONTENT_URI;
@@ -41555,6 +41556,7 @@
method public void onNotificationRemoved(android.service.notification.StatusBarNotification);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, int);
+ method public void onStatusBarIconsBehaviorChanged(boolean);
method public final void requestInterruptionFilter(int);
method public final void requestListenerHints(int);
method public static void requestRebind(android.content.ComponentName);
@@ -52887,6 +52889,9 @@
public final class UserDataRemovalRequest implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public String getPackageName();
+ method @NonNull public java.util.List<android.view.contentcapture.UserDataRemovalRequest.UriRequest> getUriRequests();
+ method public boolean isForEverything();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.contentcapture.UserDataRemovalRequest> CREATOR;
}
@@ -52898,6 +52903,11 @@
method @NonNull public android.view.contentcapture.UserDataRemovalRequest.Builder forEverything();
}
+ public final class UserDataRemovalRequest.UriRequest {
+ method @NonNull public android.net.Uri getUri();
+ method @NonNull public boolean isRecursive();
+ }
+
}
package android.view.inputmethod {
@@ -58117,13 +58127,13 @@
ctor public ByteArrayOutputStream(int);
method public void reset();
method public int size();
- method public byte[] toByteArray();
+ method @NonNull public byte[] toByteArray();
method @NonNull public String toString(@NonNull String) throws java.io.UnsupportedEncodingException;
method @Deprecated @NonNull public String toString(int);
method public void write(int);
- method public void write(byte[], int, int);
+ method public void write(@NonNull byte[], int, int);
method public void writeTo(@NonNull java.io.OutputStream) throws java.io.IOException;
- field protected byte[] buf;
+ field @NonNull protected byte[] buf;
field protected int count;
}
@@ -58294,12 +58304,12 @@
method public boolean isHidden();
method public long lastModified();
method public long length();
- method public String[] list();
- method public String[] list(@Nullable java.io.FilenameFilter);
- method public java.io.File[] listFiles();
- method public java.io.File[] listFiles(@Nullable java.io.FilenameFilter);
- method public java.io.File[] listFiles(@Nullable java.io.FileFilter);
- method public static java.io.File[] listRoots();
+ method @Nullable public String[] list();
+ method @Nullable public String[] list(@Nullable java.io.FilenameFilter);
+ method @Nullable public java.io.File[] listFiles();
+ method @Nullable public java.io.File[] listFiles(@Nullable java.io.FilenameFilter);
+ method @Nullable public java.io.File[] listFiles(@Nullable java.io.FileFilter);
+ method @NonNull public static java.io.File[] listRoots();
method public boolean mkdir();
method public boolean mkdirs();
method public boolean renameTo(@NonNull java.io.File);
@@ -58788,8 +58798,8 @@
method protected void clearError();
method public void close();
method public void flush();
- method @NonNull public java.io.PrintWriter format(@NonNull String, java.lang.Object...);
- method @NonNull public java.io.PrintWriter format(@Nullable java.util.Locale, @NonNull String, java.lang.Object...);
+ method @NonNull public java.io.PrintWriter format(@NonNull String, @NonNull java.lang.Object...);
+ method @NonNull public java.io.PrintWriter format(@Nullable java.util.Locale, @NonNull String, @NonNull java.lang.Object...);
method public void print(boolean);
method public void print(char);
method public void print(int);
@@ -58799,8 +58809,8 @@
method public void print(char[]);
method public void print(@Nullable String);
method public void print(@Nullable Object);
- method @NonNull public java.io.PrintWriter printf(@NonNull String, java.lang.Object...);
- method @NonNull public java.io.PrintWriter printf(@Nullable java.util.Locale, @NonNull String, java.lang.Object...);
+ method @NonNull public java.io.PrintWriter printf(@NonNull String, @NonNull java.lang.Object...);
+ method @NonNull public java.io.PrintWriter printf(@Nullable java.util.Locale, @NonNull String, @NonNull java.lang.Object...);
method public void println();
method public void println(boolean);
method public void println(char);
@@ -59626,45 +59636,45 @@
method @NonNull public static Class<?> forName(@NonNull String) throws java.lang.ClassNotFoundException;
method @NonNull public static Class<?> forName(@NonNull String, boolean, @Nullable ClassLoader) throws java.lang.ClassNotFoundException;
method @Nullable public <A extends java.lang.annotation.Annotation> A getAnnotation(@NonNull Class<A>);
- method public java.lang.annotation.Annotation[] getAnnotations();
+ method @NonNull public java.lang.annotation.Annotation[] getAnnotations();
method @NonNull public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(@NonNull Class<A>);
method @Nullable public String getCanonicalName();
method @Nullable public ClassLoader getClassLoader();
- method public Class<?>[] getClasses();
+ method @NonNull public Class<?>[] getClasses();
method @Nullable public Class<?> getComponentType();
- method @NonNull public java.lang.reflect.Constructor<T> getConstructor(Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
- method public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException;
+ method @NonNull public java.lang.reflect.Constructor<T> getConstructor(@Nullable Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
+ method @NonNull public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException;
method @Nullable public <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(@NonNull Class<A>);
- method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
- method public Class<?>[] getDeclaredClasses();
- method @NonNull public java.lang.reflect.Constructor<T> getDeclaredConstructor(Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
- method public java.lang.reflect.Constructor<?>[] getDeclaredConstructors() throws java.lang.SecurityException;
+ method @NonNull public java.lang.annotation.Annotation[] getDeclaredAnnotations();
+ method @NonNull public Class<?>[] getDeclaredClasses();
+ method @NonNull public java.lang.reflect.Constructor<T> getDeclaredConstructor(@Nullable Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
+ method @NonNull public java.lang.reflect.Constructor<?>[] getDeclaredConstructors() throws java.lang.SecurityException;
method @NonNull public java.lang.reflect.Field getDeclaredField(@NonNull String) throws java.lang.NoSuchFieldException;
- method public java.lang.reflect.Field[] getDeclaredFields();
- method @NonNull public java.lang.reflect.Method getDeclaredMethod(@NonNull String, Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
- method public java.lang.reflect.Method[] getDeclaredMethods() throws java.lang.SecurityException;
+ method @NonNull public java.lang.reflect.Field[] getDeclaredFields();
+ method @NonNull public java.lang.reflect.Method getDeclaredMethod(@NonNull String, @Nullable Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
+ method @NonNull public java.lang.reflect.Method[] getDeclaredMethods() throws java.lang.SecurityException;
method @Nullable public Class<?> getDeclaringClass();
method @Nullable public Class<?> getEnclosingClass();
method @Nullable public java.lang.reflect.Constructor<?> getEnclosingConstructor();
method @Nullable public java.lang.reflect.Method getEnclosingMethod();
- method public T[] getEnumConstants();
+ method @Nullable public T[] getEnumConstants();
method @NonNull public java.lang.reflect.Field getField(@NonNull String) throws java.lang.NoSuchFieldException;
- method public java.lang.reflect.Field[] getFields() throws java.lang.SecurityException;
- method public java.lang.reflect.Type[] getGenericInterfaces();
+ method @NonNull public java.lang.reflect.Field[] getFields() throws java.lang.SecurityException;
+ method @NonNull public java.lang.reflect.Type[] getGenericInterfaces();
method @Nullable public java.lang.reflect.Type getGenericSuperclass();
- method public Class<?>[] getInterfaces();
- method @NonNull public java.lang.reflect.Method getMethod(@NonNull String, Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
- method public java.lang.reflect.Method[] getMethods() throws java.lang.SecurityException;
+ method @NonNull public Class<?>[] getInterfaces();
+ method @NonNull public java.lang.reflect.Method getMethod(@NonNull String, @Nullable Class<?>...) throws java.lang.NoSuchMethodException, java.lang.SecurityException;
+ method @NonNull public java.lang.reflect.Method[] getMethods() throws java.lang.SecurityException;
method public int getModifiers();
method @NonNull public String getName();
method @Nullable public Package getPackage();
method @Nullable public java.security.ProtectionDomain getProtectionDomain();
method @Nullable public java.net.URL getResource(@NonNull String);
method @Nullable public java.io.InputStream getResourceAsStream(@NonNull String);
- method public Object[] getSigners();
+ method @Nullable public Object[] getSigners();
method @NonNull public String getSimpleName();
method @Nullable public Class<? super T> getSuperclass();
- method public java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters();
+ method @NonNull public java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters();
method public boolean isAnnotation();
method public boolean isAnonymousClass();
method public boolean isArray();
@@ -60551,8 +60561,8 @@
method @NonNull public static String copyValueOf(char[]);
method public boolean endsWith(@NonNull String);
method public boolean equalsIgnoreCase(@Nullable String);
- method @NonNull public static String format(@NonNull String, java.lang.Object...);
- method @NonNull public static String format(@NonNull java.util.Locale, @NonNull String, java.lang.Object...);
+ method @NonNull public static String format(@NonNull String, @NonNull java.lang.Object...);
+ method @NonNull public static String format(@NonNull java.util.Locale, @NonNull String, @NonNull java.lang.Object...);
method @Deprecated public void getBytes(int, int, byte[], int);
method public byte[] getBytes(@NonNull String) throws java.io.UnsupportedEncodingException;
method public byte[] getBytes(@NonNull java.nio.charset.Charset);
@@ -60564,7 +60574,7 @@
method public int indexOf(@NonNull String, int);
method @NonNull public String intern();
method public boolean isEmpty();
- method @NonNull public static String join(@NonNull CharSequence, java.lang.CharSequence...);
+ method @NonNull public static String join(@NonNull CharSequence, @Nullable java.lang.CharSequence...);
method @NonNull public static String join(@NonNull CharSequence, @NonNull Iterable<? extends java.lang.CharSequence>);
method public int lastIndexOf(int);
method public int lastIndexOf(int, int);
@@ -60579,8 +60589,8 @@
method @NonNull public String replace(@NonNull CharSequence, @NonNull CharSequence);
method @NonNull public String replaceAll(@NonNull String, @NonNull String);
method @NonNull public String replaceFirst(@NonNull String, @NonNull String);
- method public String[] split(@NonNull String, int);
- method public String[] split(@NonNull String);
+ method @NonNull public String[] split(@NonNull String, int);
+ method @NonNull public String[] split(@NonNull String);
method public boolean startsWith(@NonNull String, int);
method public boolean startsWith(@NonNull String);
method @NonNull public CharSequence subSequence(int, int);
@@ -60781,7 +60791,7 @@
method public long getId();
method @NonNull public final String getName();
method public final int getPriority();
- method public StackTraceElement[] getStackTrace();
+ method @NonNull public StackTraceElement[] getStackTrace();
method @NonNull public java.lang.Thread.State getState();
method @Nullable public final ThreadGroup getThreadGroup();
method @Nullable public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
@@ -60879,13 +60889,13 @@
method @Nullable public Throwable getCause();
method @Nullable public String getLocalizedMessage();
method @Nullable public String getMessage();
- method public StackTraceElement[] getStackTrace();
- method public final Throwable[] getSuppressed();
+ method @NonNull public StackTraceElement[] getStackTrace();
+ method @NonNull public final Throwable[] getSuppressed();
method @NonNull public Throwable initCause(@Nullable Throwable);
method public void printStackTrace();
method public void printStackTrace(@NonNull java.io.PrintStream);
method public void printStackTrace(@NonNull java.io.PrintWriter);
- method public void setStackTrace(StackTraceElement[]);
+ method public void setStackTrace(@NonNull StackTraceElement[]);
}
public class TypeNotPresentException extends java.lang.RuntimeException {
@@ -61208,8 +61218,8 @@
public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
ctor protected AccessibleObject();
method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>);
- method public java.lang.annotation.Annotation[] getAnnotations();
- method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
+ method @NonNull public java.lang.annotation.Annotation[] getAnnotations();
+ method @NonNull public java.lang.annotation.Annotation[] getDeclaredAnnotations();
method public boolean isAccessible();
method public static void setAccessible(java.lang.reflect.AccessibleObject[], boolean) throws java.lang.SecurityException;
method public void setAccessible(boolean) throws java.lang.SecurityException;
@@ -61217,10 +61227,10 @@
public interface AnnotatedElement {
method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>);
- method public java.lang.annotation.Annotation[] getAnnotations();
+ method @NonNull public java.lang.annotation.Annotation[] getAnnotations();
method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(@NonNull Class<T>);
method @Nullable public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(@NonNull Class<T>);
- method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
+ method @NonNull public java.lang.annotation.Annotation[] getDeclaredAnnotations();
method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(@NonNull Class<T>);
method public default boolean isAnnotationPresent(@NonNull Class<? extends java.lang.annotation.Annotation>);
}
@@ -61255,20 +61265,20 @@
method public int getModifiers();
method @NonNull public String getName();
method public java.lang.annotation.Annotation[][] getParameterAnnotations();
- method public Class<?>[] getParameterTypes();
+ method @NonNull public Class<?>[] getParameterTypes();
method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters();
method @NonNull public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
method @NonNull public String toGenericString();
}
public abstract class Executable extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
- method public abstract Class<?>[] getExceptionTypes();
- method public java.lang.reflect.Type[] getGenericExceptionTypes();
- method public java.lang.reflect.Type[] getGenericParameterTypes();
- method public abstract java.lang.annotation.Annotation[][] getParameterAnnotations();
+ method @NonNull public abstract Class<?>[] getExceptionTypes();
+ method @NonNull public java.lang.reflect.Type[] getGenericExceptionTypes();
+ method @NonNull public java.lang.reflect.Type[] getGenericParameterTypes();
+ method @NonNull public abstract java.lang.annotation.Annotation[][] getParameterAnnotations();
method public int getParameterCount();
- method public abstract Class<?>[] getParameterTypes();
- method public java.lang.reflect.Parameter[] getParameters();
+ method @NonNull public abstract Class<?>[] getParameterTypes();
+ method @NonNull public java.lang.reflect.Parameter[] getParameters();
method public final boolean isAnnotationPresent(@NonNull Class<? extends java.lang.annotation.Annotation>);
method public boolean isSynthetic();
method public boolean isVarArgs();
@@ -61357,7 +61367,7 @@
method @NonNull public Class<?>[] getParameterTypes();
method @NonNull public Class<?> getReturnType();
method @NonNull public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters();
- method @Nullable public Object invoke(@Nullable Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
+ method @Nullable public Object invoke(@Nullable Object, @Nullable java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
method public boolean isBridge();
method public boolean isDefault();
method @NonNull public String toGenericString();
@@ -61400,8 +61410,8 @@
public final class Parameter implements java.lang.reflect.AnnotatedElement {
method @Nullable public <T extends java.lang.annotation.Annotation> T getAnnotation(@NonNull Class<T>);
- method public java.lang.annotation.Annotation[] getAnnotations();
- method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
+ method @NonNull public java.lang.annotation.Annotation[] getAnnotations();
+ method @NonNull public java.lang.annotation.Annotation[] getDeclaredAnnotations();
method @NonNull public java.lang.reflect.Executable getDeclaringExecutable();
method public int getModifiers();
method @NonNull public String getName();
@@ -61414,7 +61424,7 @@
}
public interface ParameterizedType extends java.lang.reflect.Type {
- method public java.lang.reflect.Type[] getActualTypeArguments();
+ method @NonNull public java.lang.reflect.Type[] getActualTypeArguments();
method @Nullable public java.lang.reflect.Type getOwnerType();
method @NonNull public java.lang.reflect.Type getRawType();
}
@@ -61422,9 +61432,9 @@
public class Proxy implements java.io.Serializable {
ctor protected Proxy(@NonNull java.lang.reflect.InvocationHandler);
method @NonNull public static java.lang.reflect.InvocationHandler getInvocationHandler(@NonNull Object) throws java.lang.IllegalArgumentException;
- method @NonNull public static Class<?> getProxyClass(@Nullable ClassLoader, Class<?>...) throws java.lang.IllegalArgumentException;
+ method @NonNull public static Class<?> getProxyClass(@Nullable ClassLoader, @NonNull Class<?>...) throws java.lang.IllegalArgumentException;
method public static boolean isProxyClass(@NonNull Class<?>);
- method @NonNull public static Object newProxyInstance(@Nullable ClassLoader, Class<?>[], @NonNull java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException;
+ method @NonNull public static Object newProxyInstance(@Nullable ClassLoader, @NonNull Class<?>[], @NonNull java.lang.reflect.InvocationHandler) throws java.lang.IllegalArgumentException;
field protected java.lang.reflect.InvocationHandler h;
}
@@ -61438,7 +61448,7 @@
}
public interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> extends java.lang.reflect.Type {
- method public java.lang.reflect.Type[] getBounds();
+ method @NonNull public java.lang.reflect.Type[] getBounds();
method @NonNull public D getGenericDeclaration();
method @NonNull public String getName();
}
@@ -61450,8 +61460,8 @@
}
public interface WildcardType extends java.lang.reflect.Type {
- method public java.lang.reflect.Type[] getLowerBounds();
- method public java.lang.reflect.Type[] getUpperBounds();
+ method @NonNull public java.lang.reflect.Type[] getLowerBounds();
+ method @NonNull public java.lang.reflect.Type[] getUpperBounds();
}
}
@@ -62495,7 +62505,7 @@
public abstract class ByteBuffer extends java.nio.Buffer implements java.lang.Comparable<java.nio.ByteBuffer> {
method @NonNull public static java.nio.ByteBuffer allocate(int);
method @NonNull public static java.nio.ByteBuffer allocateDirect(int);
- method public final byte[] array();
+ method @NonNull public final byte[] array();
method public final int arrayOffset();
method @NonNull public abstract java.nio.CharBuffer asCharBuffer();
method @NonNull public abstract java.nio.DoubleBuffer asDoubleBuffer();
@@ -62509,8 +62519,8 @@
method @NonNull public abstract java.nio.ByteBuffer duplicate();
method public abstract byte get();
method public abstract byte get(int);
- method @NonNull public java.nio.ByteBuffer get(byte[], int, int);
- method @NonNull public java.nio.ByteBuffer get(byte[]);
+ method @NonNull public java.nio.ByteBuffer get(@NonNull byte[], int, int);
+ method @NonNull public java.nio.ByteBuffer get(@NonNull byte[]);
method public abstract char getChar();
method public abstract char getChar(int);
method public abstract double getDouble();
@@ -62529,8 +62539,8 @@
method @NonNull public abstract java.nio.ByteBuffer put(byte);
method @NonNull public abstract java.nio.ByteBuffer put(int, byte);
method @NonNull public java.nio.ByteBuffer put(@NonNull java.nio.ByteBuffer);
- method @NonNull public java.nio.ByteBuffer put(byte[], int, int);
- method @NonNull public final java.nio.ByteBuffer put(byte[]);
+ method @NonNull public java.nio.ByteBuffer put(@NonNull byte[], int, int);
+ method @NonNull public final java.nio.ByteBuffer put(@NonNull byte[]);
method @NonNull public abstract java.nio.ByteBuffer putChar(char);
method @NonNull public abstract java.nio.ByteBuffer putChar(int, char);
method @NonNull public abstract java.nio.ByteBuffer putDouble(double);
@@ -62544,8 +62554,8 @@
method @NonNull public abstract java.nio.ByteBuffer putShort(short);
method @NonNull public abstract java.nio.ByteBuffer putShort(int, short);
method @NonNull public abstract java.nio.ByteBuffer slice();
- method @NonNull public static java.nio.ByteBuffer wrap(byte[], int, int);
- method @NonNull public static java.nio.ByteBuffer wrap(byte[]);
+ method @NonNull public static java.nio.ByteBuffer wrap(@NonNull byte[], int, int);
+ method @NonNull public static java.nio.ByteBuffer wrap(@NonNull byte[]);
}
public final class ByteOrder {
@@ -64378,20 +64388,20 @@
public abstract class MessageDigest extends java.security.MessageDigestSpi {
ctor protected MessageDigest(@NonNull String);
- method public byte[] digest();
- method public int digest(byte[], int, int) throws java.security.DigestException;
- method public byte[] digest(byte[]);
+ method @NonNull public byte[] digest();
+ method public int digest(@NonNull byte[], int, int) throws java.security.DigestException;
+ method @NonNull public byte[] digest(@NonNull byte[]);
method @NonNull public final String getAlgorithm();
method public final int getDigestLength();
method @NonNull public static java.security.MessageDigest getInstance(@NonNull String) throws java.security.NoSuchAlgorithmException;
method @NonNull public static java.security.MessageDigest getInstance(@NonNull String, @NonNull String) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException;
method @NonNull public static java.security.MessageDigest getInstance(@NonNull String, @NonNull java.security.Provider) throws java.security.NoSuchAlgorithmException;
method @NonNull public final java.security.Provider getProvider();
- method public static boolean isEqual(byte[], byte[]);
+ method public static boolean isEqual(@Nullable byte[], @Nullable byte[]);
method public void reset();
method public void update(byte);
- method public void update(byte[], int, int);
- method public void update(byte[]);
+ method public void update(@NonNull byte[], int, int);
+ method public void update(@NonNull byte[]);
method public final void update(@NonNull java.nio.ByteBuffer);
}
@@ -66998,7 +67008,7 @@
method @NonNull public final StringBuffer format(@NonNull Object, @NonNull StringBuffer, @NonNull java.text.FieldPosition);
method @NonNull public abstract StringBuffer format(@NonNull java.util.Date, @NonNull StringBuffer, @NonNull java.text.FieldPosition);
method @NonNull public final String format(@NonNull java.util.Date);
- method public static java.util.Locale[] getAvailableLocales();
+ method @NonNull public static java.util.Locale[] getAvailableLocales();
method @NonNull public java.util.Calendar getCalendar();
method @NonNull public static final java.text.DateFormat getDateInstance();
method @NonNull public static final java.text.DateFormat getDateInstance(int);
@@ -67238,7 +67248,7 @@
method @NonNull public final String format(long);
method @NonNull public abstract StringBuffer format(double, @NonNull StringBuffer, @NonNull java.text.FieldPosition);
method @NonNull public abstract StringBuffer format(long, @NonNull StringBuffer, @NonNull java.text.FieldPosition);
- method public static java.util.Locale[] getAvailableLocales();
+ method @NonNull public static java.util.Locale[] getAvailableLocales();
method @Nullable public java.util.Currency getCurrency();
method @NonNull public static final java.text.NumberFormat getCurrencyInstance();
method @NonNull public static java.text.NumberFormat getCurrencyInstance(@NonNull java.util.Locale);
@@ -68892,8 +68902,8 @@
method public boolean remove(@Nullable Object);
method public boolean removeAll(@NonNull java.util.Collection<?>);
method public boolean retainAll(@NonNull java.util.Collection<?>);
- method public Object[] toArray();
- method public <T> T[] toArray(T[]);
+ method @NonNull public Object[] toArray();
+ method @NonNull public <T> T[] toArray(@NonNull T[]);
}
public abstract class AbstractList<E> extends java.util.AbstractCollection<E> implements java.util.List<E> {
@@ -69002,161 +69012,161 @@
}
public class Arrays {
- method @NonNull @java.lang.SafeVarargs public static <T> java.util.List<T> asList(T...);
- method public static int binarySearch(long[], long);
- method public static int binarySearch(long[], int, int, long);
- method public static int binarySearch(int[], int);
- method public static int binarySearch(int[], int, int, int);
- method public static int binarySearch(short[], short);
- method public static int binarySearch(short[], int, int, short);
- method public static int binarySearch(char[], char);
- method public static int binarySearch(char[], int, int, char);
- method public static int binarySearch(byte[], byte);
- method public static int binarySearch(byte[], int, int, byte);
- method public static int binarySearch(double[], double);
- method public static int binarySearch(double[], int, int, double);
- method public static int binarySearch(float[], float);
- method public static int binarySearch(float[], int, int, float);
- method public static int binarySearch(Object[], @NonNull Object);
- method public static int binarySearch(Object[], int, int, @NonNull Object);
- method public static <T> int binarySearch(T[], T, @Nullable java.util.Comparator<? super T>);
- method public static <T> int binarySearch(T[], int, int, T, @Nullable java.util.Comparator<? super T>);
- method public static <T> T[] copyOf(T[], int);
- method public static <T, U> T[] copyOf(U[], int, @NonNull Class<? extends T[]>);
- method public static byte[] copyOf(byte[], int);
- method public static short[] copyOf(short[], int);
- method public static int[] copyOf(int[], int);
- method public static long[] copyOf(long[], int);
- method public static char[] copyOf(char[], int);
- method public static float[] copyOf(float[], int);
- method public static double[] copyOf(double[], int);
- method public static boolean[] copyOf(boolean[], int);
- method public static <T> T[] copyOfRange(T[], int, int);
- method public static <T, U> T[] copyOfRange(U[], int, int, @NonNull Class<? extends T[]>);
- method public static byte[] copyOfRange(byte[], int, int);
- method public static short[] copyOfRange(short[], int, int);
- method public static int[] copyOfRange(int[], int, int);
- method public static long[] copyOfRange(long[], int, int);
- method public static char[] copyOfRange(char[], int, int);
- method public static float[] copyOfRange(float[], int, int);
- method public static double[] copyOfRange(double[], int, int);
- method public static boolean[] copyOfRange(boolean[], int, int);
- method public static boolean deepEquals(Object[], Object[]);
- method public static int deepHashCode(Object[]);
- method @NonNull public static String deepToString(Object[]);
- method public static boolean equals(long[], long[]);
- method public static boolean equals(int[], int[]);
- method public static boolean equals(short[], short[]);
- method public static boolean equals(char[], char[]);
- method public static boolean equals(byte[], byte[]);
- method public static boolean equals(boolean[], boolean[]);
- method public static boolean equals(double[], double[]);
- method public static boolean equals(float[], float[]);
- method public static boolean equals(Object[], Object[]);
- method public static void fill(long[], long);
- method public static void fill(long[], int, int, long);
- method public static void fill(int[], int);
- method public static void fill(int[], int, int, int);
- method public static void fill(short[], short);
- method public static void fill(short[], int, int, short);
- method public static void fill(char[], char);
- method public static void fill(char[], int, int, char);
- method public static void fill(byte[], byte);
- method public static void fill(byte[], int, int, byte);
- method public static void fill(boolean[], boolean);
- method public static void fill(boolean[], int, int, boolean);
- method public static void fill(double[], double);
- method public static void fill(double[], int, int, double);
- method public static void fill(float[], float);
- method public static void fill(float[], int, int, float);
- method public static void fill(Object[], @Nullable Object);
- method public static void fill(Object[], int, int, @Nullable Object);
- method public static int hashCode(long[]);
- method public static int hashCode(int[]);
- method public static int hashCode(short[]);
- method public static int hashCode(char[]);
- method public static int hashCode(byte[]);
- method public static int hashCode(boolean[]);
- method public static int hashCode(float[]);
- method public static int hashCode(double[]);
- method public static int hashCode(Object[]);
- method public static <T> void parallelPrefix(T[], @NonNull java.util.function.BinaryOperator<T>);
- method public static <T> void parallelPrefix(T[], int, int, @NonNull java.util.function.BinaryOperator<T>);
- method public static void parallelPrefix(long[], @NonNull java.util.function.LongBinaryOperator);
- method public static void parallelPrefix(long[], int, int, @NonNull java.util.function.LongBinaryOperator);
- method public static void parallelPrefix(double[], @NonNull java.util.function.DoubleBinaryOperator);
- method public static void parallelPrefix(double[], int, int, @NonNull java.util.function.DoubleBinaryOperator);
- method public static void parallelPrefix(int[], @NonNull java.util.function.IntBinaryOperator);
- method public static void parallelPrefix(int[], int, int, @NonNull java.util.function.IntBinaryOperator);
- method public static <T> void parallelSetAll(T[], @NonNull java.util.function.IntFunction<? extends T>);
- method public static void parallelSetAll(int[], @NonNull java.util.function.IntUnaryOperator);
- method public static void parallelSetAll(long[], @NonNull java.util.function.IntToLongFunction);
- method public static void parallelSetAll(double[], @NonNull java.util.function.IntToDoubleFunction);
- method public static void parallelSort(byte[]);
- method public static void parallelSort(byte[], int, int);
- method public static void parallelSort(char[]);
- method public static void parallelSort(char[], int, int);
- method public static void parallelSort(short[]);
- method public static void parallelSort(short[], int, int);
- method public static void parallelSort(int[]);
- method public static void parallelSort(int[], int, int);
- method public static void parallelSort(long[]);
- method public static void parallelSort(long[], int, int);
- method public static void parallelSort(float[]);
- method public static void parallelSort(float[], int, int);
- method public static void parallelSort(double[]);
- method public static void parallelSort(double[], int, int);
- method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[]);
- method public static <T extends java.lang.Comparable<? super T>> void parallelSort(T[], int, int);
- method public static <T> void parallelSort(T[], @Nullable java.util.Comparator<? super T>);
- method public static <T> void parallelSort(T[], int, int, @Nullable java.util.Comparator<? super T>);
- method public static <T> void setAll(T[], @NonNull java.util.function.IntFunction<? extends T>);
- method public static void setAll(int[], @NonNull java.util.function.IntUnaryOperator);
- method public static void setAll(long[], @NonNull java.util.function.IntToLongFunction);
- method public static void setAll(double[], @NonNull java.util.function.IntToDoubleFunction);
- method public static void sort(int[]);
- method public static void sort(int[], int, int);
- method public static void sort(long[]);
- method public static void sort(long[], int, int);
- method public static void sort(short[]);
- method public static void sort(short[], int, int);
- method public static void sort(char[]);
- method public static void sort(char[], int, int);
- method public static void sort(byte[]);
- method public static void sort(byte[], int, int);
- method public static void sort(float[]);
- method public static void sort(float[], int, int);
- method public static void sort(double[]);
- method public static void sort(double[], int, int);
- method public static void sort(Object[]);
- method public static void sort(Object[], int, int);
- method public static <T> void sort(T[], @Nullable java.util.Comparator<? super T>);
- method public static <T> void sort(T[], int, int, @Nullable java.util.Comparator<? super T>);
- method @NonNull public static <T> java.util.Spliterator<T> spliterator(T[]);
- method @NonNull public static <T> java.util.Spliterator<T> spliterator(T[], int, int);
- method @NonNull public static java.util.Spliterator.OfInt spliterator(int[]);
- method @NonNull public static java.util.Spliterator.OfInt spliterator(int[], int, int);
- method @NonNull public static java.util.Spliterator.OfLong spliterator(long[]);
- method @NonNull public static java.util.Spliterator.OfLong spliterator(long[], int, int);
- method @NonNull public static java.util.Spliterator.OfDouble spliterator(double[]);
- method @NonNull public static java.util.Spliterator.OfDouble spliterator(double[], int, int);
- method @NonNull public static <T> java.util.stream.Stream<T> stream(T[]);
- method @NonNull public static <T> java.util.stream.Stream<T> stream(T[], int, int);
- method @NonNull public static java.util.stream.IntStream stream(int[]);
- method @NonNull public static java.util.stream.IntStream stream(int[], int, int);
- method @NonNull public static java.util.stream.LongStream stream(long[]);
- method @NonNull public static java.util.stream.LongStream stream(long[], int, int);
- method @NonNull public static java.util.stream.DoubleStream stream(double[]);
- method @NonNull public static java.util.stream.DoubleStream stream(double[], int, int);
- method @NonNull public static String toString(long[]);
- method @NonNull public static String toString(int[]);
- method @NonNull public static String toString(short[]);
- method @NonNull public static String toString(char[]);
- method @NonNull public static String toString(byte[]);
- method @NonNull public static String toString(boolean[]);
- method @NonNull public static String toString(float[]);
- method @NonNull public static String toString(double[]);
- method @NonNull public static String toString(Object[]);
+ method @NonNull @java.lang.SafeVarargs public static <T> java.util.List<T> asList(@NonNull T...);
+ method public static int binarySearch(@NonNull long[], long);
+ method public static int binarySearch(@NonNull long[], int, int, long);
+ method public static int binarySearch(@NonNull int[], int);
+ method public static int binarySearch(@NonNull int[], int, int, int);
+ method public static int binarySearch(@NonNull short[], short);
+ method public static int binarySearch(@NonNull short[], int, int, short);
+ method public static int binarySearch(@NonNull char[], char);
+ method public static int binarySearch(@NonNull char[], int, int, char);
+ method public static int binarySearch(@NonNull byte[], byte);
+ method public static int binarySearch(@NonNull byte[], int, int, byte);
+ method public static int binarySearch(@NonNull double[], double);
+ method public static int binarySearch(@NonNull double[], int, int, double);
+ method public static int binarySearch(@NonNull float[], float);
+ method public static int binarySearch(@NonNull float[], int, int, float);
+ method public static int binarySearch(@NonNull Object[], @NonNull Object);
+ method public static int binarySearch(@NonNull Object[], int, int, @NonNull Object);
+ method public static <T> int binarySearch(@NonNull T[], T, @Nullable java.util.Comparator<? super T>);
+ method public static <T> int binarySearch(@NonNull T[], int, int, T, @Nullable java.util.Comparator<? super T>);
+ method @NonNull public static <T> T[] copyOf(@NonNull T[], int);
+ method @NonNull public static <T, U> T[] copyOf(@NonNull U[], int, @NonNull Class<? extends T[]>);
+ method @NonNull public static byte[] copyOf(@NonNull byte[], int);
+ method @NonNull public static short[] copyOf(@NonNull short[], int);
+ method @NonNull public static int[] copyOf(@NonNull int[], int);
+ method @NonNull public static long[] copyOf(@NonNull long[], int);
+ method @NonNull public static char[] copyOf(@NonNull char[], int);
+ method @NonNull public static float[] copyOf(@NonNull float[], int);
+ method @NonNull public static double[] copyOf(@NonNull double[], int);
+ method @NonNull public static boolean[] copyOf(@NonNull boolean[], int);
+ method @NonNull public static <T> T[] copyOfRange(@NonNull T[], int, int);
+ method @NonNull public static <T, U> T[] copyOfRange(@NonNull U[], int, int, @NonNull Class<? extends T[]>);
+ method @NonNull public static byte[] copyOfRange(@NonNull byte[], int, int);
+ method @NonNull public static short[] copyOfRange(@NonNull short[], int, int);
+ method @NonNull public static int[] copyOfRange(@NonNull int[], int, int);
+ method @NonNull public static long[] copyOfRange(@NonNull long[], int, int);
+ method @NonNull public static char[] copyOfRange(@NonNull char[], int, int);
+ method @NonNull public static float[] copyOfRange(@NonNull float[], int, int);
+ method @NonNull public static double[] copyOfRange(@NonNull double[], int, int);
+ method @NonNull public static boolean[] copyOfRange(@NonNull boolean[], int, int);
+ method public static boolean deepEquals(@Nullable Object[], @Nullable Object[]);
+ method public static int deepHashCode(@Nullable Object[]);
+ method @NonNull public static String deepToString(@Nullable Object[]);
+ method public static boolean equals(@Nullable long[], @Nullable long[]);
+ method public static boolean equals(@Nullable int[], @Nullable int[]);
+ method public static boolean equals(@Nullable short[], @Nullable short[]);
+ method public static boolean equals(@Nullable char[], @Nullable char[]);
+ method public static boolean equals(@Nullable byte[], @Nullable byte[]);
+ method public static boolean equals(@Nullable boolean[], @Nullable boolean[]);
+ method public static boolean equals(@Nullable double[], @Nullable double[]);
+ method public static boolean equals(@Nullable float[], @Nullable float[]);
+ method public static boolean equals(@Nullable Object[], @Nullable Object[]);
+ method public static void fill(@NonNull long[], long);
+ method public static void fill(@NonNull long[], int, int, long);
+ method public static void fill(@NonNull int[], int);
+ method public static void fill(@NonNull int[], int, int, int);
+ method public static void fill(@NonNull short[], short);
+ method public static void fill(@NonNull short[], int, int, short);
+ method public static void fill(@NonNull char[], char);
+ method public static void fill(@NonNull char[], int, int, char);
+ method public static void fill(@NonNull byte[], byte);
+ method public static void fill(@NonNull byte[], int, int, byte);
+ method public static void fill(@NonNull boolean[], boolean);
+ method public static void fill(@NonNull boolean[], int, int, boolean);
+ method public static void fill(@NonNull double[], double);
+ method public static void fill(@NonNull double[], int, int, double);
+ method public static void fill(@NonNull float[], float);
+ method public static void fill(@NonNull float[], int, int, float);
+ method public static void fill(@NonNull Object[], @Nullable Object);
+ method public static void fill(@NonNull Object[], int, int, @Nullable Object);
+ method public static int hashCode(@Nullable long[]);
+ method public static int hashCode(@Nullable int[]);
+ method public static int hashCode(@Nullable short[]);
+ method public static int hashCode(@Nullable char[]);
+ method public static int hashCode(@Nullable byte[]);
+ method public static int hashCode(@Nullable boolean[]);
+ method public static int hashCode(@Nullable float[]);
+ method public static int hashCode(@Nullable double[]);
+ method public static int hashCode(@Nullable Object[]);
+ method public static <T> void parallelPrefix(@NonNull T[], @NonNull java.util.function.BinaryOperator<T>);
+ method public static <T> void parallelPrefix(@NonNull T[], int, int, @NonNull java.util.function.BinaryOperator<T>);
+ method public static void parallelPrefix(@NonNull long[], @NonNull java.util.function.LongBinaryOperator);
+ method public static void parallelPrefix(@NonNull long[], int, int, @NonNull java.util.function.LongBinaryOperator);
+ method public static void parallelPrefix(@NonNull double[], @NonNull java.util.function.DoubleBinaryOperator);
+ method public static void parallelPrefix(@NonNull double[], int, int, @NonNull java.util.function.DoubleBinaryOperator);
+ method public static void parallelPrefix(@NonNull int[], @NonNull java.util.function.IntBinaryOperator);
+ method public static void parallelPrefix(@NonNull int[], int, int, @NonNull java.util.function.IntBinaryOperator);
+ method public static <T> void parallelSetAll(@NonNull T[], @NonNull java.util.function.IntFunction<? extends T>);
+ method public static void parallelSetAll(@NonNull int[], @NonNull java.util.function.IntUnaryOperator);
+ method public static void parallelSetAll(@NonNull long[], @NonNull java.util.function.IntToLongFunction);
+ method public static void parallelSetAll(@NonNull double[], @NonNull java.util.function.IntToDoubleFunction);
+ method public static void parallelSort(@NonNull byte[]);
+ method public static void parallelSort(@NonNull byte[], int, int);
+ method public static void parallelSort(@NonNull char[]);
+ method public static void parallelSort(@NonNull char[], int, int);
+ method public static void parallelSort(@NonNull short[]);
+ method public static void parallelSort(@NonNull short[], int, int);
+ method public static void parallelSort(@NonNull int[]);
+ method public static void parallelSort(@NonNull int[], int, int);
+ method public static void parallelSort(@NonNull long[]);
+ method public static void parallelSort(@NonNull long[], int, int);
+ method public static void parallelSort(@NonNull float[]);
+ method public static void parallelSort(@NonNull float[], int, int);
+ method public static void parallelSort(@NonNull double[]);
+ method public static void parallelSort(@NonNull double[], int, int);
+ method public static <T extends java.lang.Comparable<? super T>> void parallelSort(@NonNull T[]);
+ method public static <T extends java.lang.Comparable<? super T>> void parallelSort(@NonNull T[], int, int);
+ method public static <T> void parallelSort(@NonNull T[], @Nullable java.util.Comparator<? super T>);
+ method public static <T> void parallelSort(@NonNull T[], int, int, @Nullable java.util.Comparator<? super T>);
+ method public static <T> void setAll(@NonNull T[], @NonNull java.util.function.IntFunction<? extends T>);
+ method public static void setAll(@NonNull int[], @NonNull java.util.function.IntUnaryOperator);
+ method public static void setAll(@NonNull long[], @NonNull java.util.function.IntToLongFunction);
+ method public static void setAll(@NonNull double[], @NonNull java.util.function.IntToDoubleFunction);
+ method public static void sort(@NonNull int[]);
+ method public static void sort(@NonNull int[], int, int);
+ method public static void sort(@NonNull long[]);
+ method public static void sort(@NonNull long[], int, int);
+ method public static void sort(@NonNull short[]);
+ method public static void sort(@NonNull short[], int, int);
+ method public static void sort(@NonNull char[]);
+ method public static void sort(@NonNull char[], int, int);
+ method public static void sort(@NonNull byte[]);
+ method public static void sort(@NonNull byte[], int, int);
+ method public static void sort(@NonNull float[]);
+ method public static void sort(@NonNull float[], int, int);
+ method public static void sort(@NonNull double[]);
+ method public static void sort(@NonNull double[], int, int);
+ method public static void sort(@NonNull Object[]);
+ method public static void sort(@NonNull Object[], int, int);
+ method public static <T> void sort(@NonNull T[], @Nullable java.util.Comparator<? super T>);
+ method public static <T> void sort(@NonNull T[], int, int, @Nullable java.util.Comparator<? super T>);
+ method @NonNull public static <T> java.util.Spliterator<T> spliterator(@NonNull T[]);
+ method @NonNull public static <T> java.util.Spliterator<T> spliterator(@NonNull T[], int, int);
+ method @NonNull public static java.util.Spliterator.OfInt spliterator(@NonNull int[]);
+ method @NonNull public static java.util.Spliterator.OfInt spliterator(@NonNull int[], int, int);
+ method @NonNull public static java.util.Spliterator.OfLong spliterator(@NonNull long[]);
+ method @NonNull public static java.util.Spliterator.OfLong spliterator(@NonNull long[], int, int);
+ method @NonNull public static java.util.Spliterator.OfDouble spliterator(@NonNull double[]);
+ method @NonNull public static java.util.Spliterator.OfDouble spliterator(@NonNull double[], int, int);
+ method @NonNull public static <T> java.util.stream.Stream<T> stream(@NonNull T[]);
+ method @NonNull public static <T> java.util.stream.Stream<T> stream(@NonNull T[], int, int);
+ method @NonNull public static java.util.stream.IntStream stream(@NonNull int[]);
+ method @NonNull public static java.util.stream.IntStream stream(@NonNull int[], int, int);
+ method @NonNull public static java.util.stream.LongStream stream(@NonNull long[]);
+ method @NonNull public static java.util.stream.LongStream stream(@NonNull long[], int, int);
+ method @NonNull public static java.util.stream.DoubleStream stream(@NonNull double[]);
+ method @NonNull public static java.util.stream.DoubleStream stream(@NonNull double[], int, int);
+ method @NonNull public static String toString(@Nullable long[]);
+ method @NonNull public static String toString(@Nullable int[]);
+ method @NonNull public static String toString(@Nullable short[]);
+ method @NonNull public static String toString(@Nullable char[]);
+ method @NonNull public static String toString(@Nullable byte[]);
+ method @NonNull public static String toString(@Nullable boolean[]);
+ method @NonNull public static String toString(@Nullable float[]);
+ method @NonNull public static String toString(@Nullable double[]);
+ method @NonNull public static String toString(@Nullable Object[]);
}
public class Base64 {
@@ -69240,7 +69250,7 @@
method public int getActualMaximum(int);
method public int getActualMinimum(int);
method @NonNull public static java.util.Set<java.lang.String> getAvailableCalendarTypes();
- method public static java.util.Locale[] getAvailableLocales();
+ method @NonNull public static java.util.Locale[] getAvailableLocales();
method @NonNull public String getCalendarType();
method @Nullable public String getDisplayName(int, int, @NonNull java.util.Locale);
method @Nullable public java.util.Map<java.lang.String,java.lang.Integer> getDisplayNames(int, int, @NonNull java.util.Locale);
@@ -69328,8 +69338,8 @@
field public static final int YEAR = 1; // 0x1
field public static final int ZONE_OFFSET = 15; // 0xf
field protected boolean areFieldsSet;
- field protected int[] fields;
- field protected boolean[] isSet;
+ field @NonNull protected int[] fields;
+ field @NonNull protected boolean[] isSet;
field protected boolean isTimeSet;
field protected long time;
}
@@ -69340,7 +69350,7 @@
method @NonNull public java.util.Calendar.Builder set(int, int);
method @NonNull public java.util.Calendar.Builder setCalendarType(@NonNull String);
method @NonNull public java.util.Calendar.Builder setDate(int, int, int);
- method @NonNull public java.util.Calendar.Builder setFields(int...);
+ method @NonNull public java.util.Calendar.Builder setFields(@NonNull int...);
method @NonNull public java.util.Calendar.Builder setInstant(long);
method @NonNull public java.util.Calendar.Builder setInstant(@NonNull java.util.Date);
method @NonNull public java.util.Calendar.Builder setLenient(boolean);
@@ -69370,12 +69380,12 @@
method public int size();
method @NonNull public default java.util.Spliterator<E> spliterator();
method @NonNull public default java.util.stream.Stream<E> stream();
- method public Object[] toArray();
- method public <T> T[] toArray(T[]);
+ method @NonNull public Object[] toArray();
+ method @NonNull public <T> T[] toArray(@NonNull T[]);
}
public class Collections {
- method @java.lang.SafeVarargs public static <T> boolean addAll(@NonNull java.util.Collection<? super T>, T...);
+ method @java.lang.SafeVarargs public static <T> boolean addAll(@NonNull java.util.Collection<? super T>, @NonNull T...);
method @NonNull public static <T> java.util.Queue<T> asLifoQueue(@NonNull java.util.Deque<T>);
method public static <T> int binarySearch(@NonNull java.util.List<? extends java.lang.Comparable<? super T>>, @NonNull T);
method public static <T> int binarySearch(@NonNull java.util.List<? extends T>, T, @Nullable java.util.Comparator<? super T>);
@@ -69893,7 +69903,7 @@
method @NonNull public static java.util.List<java.lang.String> filterTags(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.lang.String>, @NonNull java.util.Locale.FilteringMode);
method @NonNull public static java.util.List<java.lang.String> filterTags(@NonNull java.util.List<java.util.Locale.LanguageRange>, @NonNull java.util.Collection<java.lang.String>);
method @NonNull public static java.util.Locale forLanguageTag(@NonNull String);
- method public static java.util.Locale[] getAvailableLocales();
+ method @NonNull public static java.util.Locale[] getAvailableLocales();
method @NonNull public String getCountry();
method @NonNull public static java.util.Locale getDefault();
method @NonNull public static java.util.Locale getDefault(@NonNull java.util.Locale.Category);
@@ -69911,8 +69921,8 @@
method @NonNull public java.util.Set<java.lang.Character> getExtensionKeys();
method @NonNull public String getISO3Country() throws java.util.MissingResourceException;
method @NonNull public String getISO3Language() throws java.util.MissingResourceException;
- method public static String[] getISOCountries();
- method public static String[] getISOLanguages();
+ method @NonNull public static String[] getISOCountries();
+ method @NonNull public static String[] getISOLanguages();
method @NonNull public String getLanguage();
method @NonNull public String getScript();
method @NonNull public java.util.Set<java.lang.String> getUnicodeLocaleAttributes();
@@ -70106,7 +70116,7 @@
method public static <T> int compare(T, T, @NonNull java.util.Comparator<? super T>);
method public static boolean deepEquals(@Nullable Object, @Nullable Object);
method public static boolean equals(@Nullable Object, @Nullable Object);
- method public static int hash(java.lang.Object...);
+ method public static int hash(@Nullable java.lang.Object...);
method public static int hashCode(@Nullable Object);
method public static boolean isNull(@Nullable Object);
method public static boolean nonNull(@Nullable Object);
@@ -70771,7 +70781,7 @@
method public void addElement(E);
method public int capacity();
method @NonNull public Object clone();
- method public void copyInto(Object[]);
+ method public void copyInto(@NonNull Object[]);
method public E elementAt(int);
method @NonNull public java.util.Enumeration<E> elements();
method public void ensureCapacity(int);
@@ -70791,7 +70801,7 @@
method public void trimToSize();
field protected int capacityIncrement;
field protected int elementCount;
- field protected Object[] elementData;
+ field @NonNull protected Object[] elementData;
}
public class WeakHashMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.Map<K,V> {
@@ -71182,7 +71192,7 @@
public class CopyOnWriteArrayList<E> implements java.lang.Cloneable java.util.List<E> java.util.RandomAccess java.io.Serializable {
ctor public CopyOnWriteArrayList();
ctor public CopyOnWriteArrayList(@NonNull java.util.Collection<? extends E>);
- ctor public CopyOnWriteArrayList(E[]);
+ ctor public CopyOnWriteArrayList(@NonNull E[]);
method public boolean add(E);
method public void add(int, E);
method public boolean addAll(@NonNull java.util.Collection<? extends E>);
@@ -71210,8 +71220,8 @@
method public E set(int, E);
method public int size();
method @NonNull public java.util.List<E> subList(int, int);
- method public Object[] toArray();
- method public <T> T[] toArray(T[]);
+ method @NonNull public Object[] toArray();
+ method @NonNull public <T> T[] toArray(@NonNull T[]);
}
public class CopyOnWriteArraySet<E> extends java.util.AbstractSet<E> implements java.io.Serializable {
@@ -72963,7 +72973,7 @@
method public void config(@NonNull java.util.function.Supplier<java.lang.String>);
method public void entering(@Nullable String, @Nullable String);
method public void entering(@Nullable String, @Nullable String, @Nullable Object);
- method public void entering(@Nullable String, @Nullable String, Object[]);
+ method public void entering(@Nullable String, @Nullable String, @Nullable Object[]);
method public void exiting(@Nullable String, @Nullable String);
method public void exiting(@Nullable String, @Nullable String, @Nullable Object);
method public void fine(@Nullable String);
@@ -72976,7 +72986,7 @@
method @NonNull public static java.util.logging.Logger getAnonymousLogger(@Nullable String);
method @Nullable public java.util.logging.Filter getFilter();
method @NonNull public static final java.util.logging.Logger getGlobal();
- method public java.util.logging.Handler[] getHandlers();
+ method @NonNull public java.util.logging.Handler[] getHandlers();
method @Nullable public java.util.logging.Level getLevel();
method @NonNull public static java.util.logging.Logger getLogger(@NonNull String);
method @NonNull public static java.util.logging.Logger getLogger(@NonNull String, @Nullable String);
@@ -72992,7 +73002,7 @@
method public void log(@NonNull java.util.logging.Level, @Nullable String);
method public void log(@NonNull java.util.logging.Level, @NonNull java.util.function.Supplier<java.lang.String>);
method public void log(@NonNull java.util.logging.Level, @Nullable String, @Nullable Object);
- method public void log(@NonNull java.util.logging.Level, @Nullable String, Object[]);
+ method public void log(@NonNull java.util.logging.Level, @Nullable String, @Nullable Object[]);
method public void log(@NonNull java.util.logging.Level, @Nullable String, @Nullable Throwable);
method public void log(@NonNull java.util.logging.Level, @Nullable Throwable, @NonNull java.util.function.Supplier<java.lang.String>);
method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String);
@@ -73003,8 +73013,8 @@
method public void logp(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable Throwable, @NonNull java.util.function.Supplier<java.lang.String>);
method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String);
method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable Object);
- method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, Object[]);
- method public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable java.util.ResourceBundle, @Nullable String, java.lang.Object...);
+ method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable Object[]);
+ method public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable java.util.ResourceBundle, @Nullable String, @Nullable java.lang.Object...);
method @Deprecated public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable String, @Nullable String, @Nullable Throwable);
method public void logrb(@NonNull java.util.logging.Level, @Nullable String, @Nullable String, @Nullable java.util.ResourceBundle, @Nullable String, @Nullable Throwable);
method public void removeHandler(@Nullable java.util.logging.Handler) throws java.lang.SecurityException;
@@ -73266,8 +73276,8 @@
method public static boolean matches(@NonNull String, @NonNull CharSequence);
method @NonNull public String pattern();
method @NonNull public static String quote(@NonNull String);
- method public String[] split(@NonNull CharSequence, int);
- method public String[] split(@NonNull CharSequence);
+ method @NonNull public String[] split(@NonNull CharSequence, int);
+ method @NonNull public String[] split(@NonNull CharSequence);
method @NonNull public java.util.stream.Stream<java.lang.String> splitAsStream(@NonNull CharSequence);
field public static final int CANON_EQ = 128; // 0x80
field public static final int CASE_INSENSITIVE = 2; // 0x2
diff --git a/api/system-current.txt b/api/system-current.txt
index e7c7b57..19b3f0e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1718,9 +1718,9 @@
public final class RollbackInfo implements android.os.Parcelable {
method public int describeContents();
method public java.util.List<android.content.pm.VersionedPackage> getCausePackages();
+ method public int getCommittedSessionId();
method public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
method public int getRollbackId();
- method public int getSessionId();
method public boolean isStaged();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
@@ -9404,17 +9404,6 @@
method public void setContentCaptureFeatureEnabled(boolean);
}
- public final class UserDataRemovalRequest implements android.os.Parcelable {
- method @NonNull public String getPackageName();
- method @NonNull public java.util.List<android.view.contentcapture.UserDataRemovalRequest.UriRequest> getUriRequests();
- method public boolean isForEverything();
- }
-
- public final class UserDataRemovalRequest.UriRequest {
- method @NonNull public android.net.Uri getUri();
- method @NonNull public boolean isRecursive();
- }
-
public final class ViewNode extends android.app.assist.AssistStructure.ViewNode {
method @Nullable public android.view.autofill.AutofillId getParentAutofillId();
}
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index 4e4b8f3..f37d2be 100644
--- a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -55,6 +55,10 @@
Status status = statsCompanionServiceCopy->pullData(mTagId, &returned_value);
if (!status.isOk()) {
ALOGW("StatsCompanionServicePuller::pull failed for %d", mTagId);
+ StatsdStats::getInstance().noteStatsCompanionPullFailed(mTagId);
+ if (status.exceptionCode() == Status::Exception::EX_TRANSACTION_FAILED) {
+ StatsdStats::getInstance().noteStatsCompanionPullBinderTransactionFailed(mTagId);
+ }
return false;
}
data->clear();
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index ba7bcc4..a6ba2ca 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -231,6 +231,9 @@
if (kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end()) {
bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data);
VLOG("pulled %d items", (int)data->size());
+ if (!ret) {
+ StatsdStats::getInstance().notePullFailed(tagId);
+ }
return ret;
} else {
VLOG("Unknown tagId %d", tagId);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index f4d0144..37ccad5 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -403,6 +403,60 @@
mSystemServerRestartSec.push_back(timeSec);
}
+void StatsdStats::notePullFailed(int atomId) {
+ lock_guard<std::mutex> lock(mLock);
+ mPulledAtomStats[atomId].pullFailed++;
+}
+
+void StatsdStats::noteStatsCompanionPullFailed(int atomId) {
+ lock_guard<std::mutex> lock(mLock);
+ mPulledAtomStats[atomId].statsCompanionPullFailed++;
+}
+
+void StatsdStats::noteStatsCompanionPullBinderTransactionFailed(int atomId) {
+ lock_guard<std::mutex> lock(mLock);
+ mPulledAtomStats[atomId].statsCompanionPullBinderTransactionFailed++;
+}
+
+void StatsdStats::noteEmptyData(int atomId) {
+ lock_guard<std::mutex> lock(mLock);
+ mPulledAtomStats[atomId].emptyData++;
+}
+
+void StatsdStats::noteHardDimensionLimitReached(int metricId) {
+ lock_guard<std::mutex> lock(mLock);
+ getAtomMetricStats(metricId).hardDimensionLimitReached++;
+}
+
+void StatsdStats::noteLateLogEventSkipped(int metricId) {
+ lock_guard<std::mutex> lock(mLock);
+ getAtomMetricStats(metricId).lateLogEventSkipped++;
+}
+
+void StatsdStats::noteSkippedForwardBuckets(int metricId) {
+ lock_guard<std::mutex> lock(mLock);
+ getAtomMetricStats(metricId).skippedForwardBuckets++;
+}
+
+void StatsdStats::noteBadValueType(int metricId) {
+ lock_guard<std::mutex> lock(mLock);
+ getAtomMetricStats(metricId).badValueType++;
+}
+
+void StatsdStats::noteConditionChangeInNextBucket(int metricId) {
+ lock_guard<std::mutex> lock(mLock);
+ getAtomMetricStats(metricId).conditionChangeInNextBucket++;
+}
+
+StatsdStats::AtomMetricStats& StatsdStats::getAtomMetricStats(int metricId) {
+ auto atomMetricStatsIter = mAtomMetricStats.find(metricId);
+ if (atomMetricStatsIter != mAtomMetricStats.end()) {
+ return atomMetricStatsIter->second;
+ }
+ auto emplaceResult = mAtomMetricStats.emplace(metricId, AtomMetricStats());
+ return emplaceResult.first->second;
+}
+
void StatsdStats::reset() {
lock_guard<std::mutex> lock(mLock);
resetInternalLocked();
@@ -442,6 +496,7 @@
pullStats.second.pullTimeout = 0;
pullStats.second.pullExceedMaxDelay = 0;
}
+ mAtomMetricStats.clear();
}
string buildTimeString(int64_t timeSec) {
@@ -713,6 +768,10 @@
android::os::statsd::writePullerStatsToStream(pair, &proto);
}
+ for (const auto& pair : mAtomMetricStats) {
+ android::os::statsd::writeAtomMetricStatsToStream(pair, &proto);
+ }
+
if (mAnomalyAlarmRegisteredStats > 0) {
uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ANOMALY_ALARM_STATS);
proto.write(FIELD_TYPE_INT32 | FIELD_ID_ANOMALY_ALARMS_REGISTERED,
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index dc647f8..01e9ca1 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -318,6 +318,53 @@
void noteLogLost(int32_t wallClockTimeSec, int32_t count, int lastError);
/**
+ * Records that the pull of an atom has failed
+ */
+ void notePullFailed(int atomId);
+
+ /**
+ * Records that the pull of StatsCompanionService atom has failed
+ */
+ void noteStatsCompanionPullFailed(int atomId);
+
+ /**
+ * Records that the pull of a StatsCompanionService atom has failed due to a failed binder
+ * transaction. This can happen when StatsCompanionService returns too
+ * much data (the max Binder parcel size is 1MB)
+ */
+ void noteStatsCompanionPullBinderTransactionFailed(int atomId);
+
+ /**
+ * A pull with no data occurred
+ */
+ void noteEmptyData(int atomId);
+
+ /**
+ * Hard limit was reached in the cardinality of an atom
+ */
+ void noteHardDimensionLimitReached(int atomId);
+
+ /**
+ * A log event was too late, arrived in the wrong bucket and was skipped
+ */
+ void noteLateLogEventSkipped(int atomId);
+
+ /**
+ * Buckets were skipped as time elapsed without any data for them
+ */
+ void noteSkippedForwardBuckets(int atomId);
+
+ /**
+ * An unsupported value type was received
+ */
+ void noteBadValueType(int atomId);
+
+ /**
+ * A condition change was too late, arrived in the wrong bucket and was skipped
+ */
+ void noteConditionChangeInNextBucket(int atomId);
+
+ /**
* Reset the historical stats. Including all stats in icebox, and the tracked stats about
* metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
* to collect stats after reset() has been called.
@@ -349,8 +396,20 @@
long dataError = 0;
long pullTimeout = 0;
long pullExceedMaxDelay = 0;
+ long pullFailed = 0;
+ long statsCompanionPullFailed = 0;
+ long statsCompanionPullBinderTransactionFailed = 0;
+ long emptyData = 0;
} PulledAtomStats;
+ typedef struct {
+ long hardDimensionLimitReached = 0;
+ long lateLogEventSkipped = 0;
+ long skippedForwardBuckets = 0;
+ long badValueType = 0;
+ long conditionChangeInNextBucket = 0;
+ } AtomMetricStats;
+
private:
StatsdStats();
@@ -378,6 +437,9 @@
// Maps PullAtomId to its stats. The size is capped by the puller atom counts.
std::map<int, PulledAtomStats> mPulledAtomStats;
+ // Maps metric ID to its stats. The size is capped by the number of metrics.
+ std::map<int, AtomMetricStats> mAtomMetricStats;
+
struct LogLossStats {
LogLossStats(int32_t sec, int32_t count, int32_t error)
: mWallClockSec(sec), mCount(count), mLastError(error) {
@@ -414,6 +476,12 @@
void addToIceBoxLocked(std::shared_ptr<ConfigStats>& stats);
+ /**
+ * Get a reference to AtomMetricStats for a metric. If none exists, create it. The reference
+ * will live as long as `this`.
+ */
+ StatsdStats::AtomMetricStats& getAtomMetricStats(int metricId);
+
FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd);
FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd);
FRIEND_TEST(StatsdStatsTest, TestConfigRemove);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 5645461..6aa8e84 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -322,6 +322,7 @@
if (eventTimeNs < mCurrentBucketStartTimeNs) {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
+ StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
return;
}
@@ -359,6 +360,12 @@
}
StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
+ if (timestampNs < mCurrentBucketStartTimeNs) {
+ // The data will be skipped in onMatchedLogEventInternalLocked, but we don't want to report
+ // for every event, just the pull
+ StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
+ }
+
for (const auto& data : allData) {
// make a copy before doing and changes
LogEvent localCopy = data->makeCopy();
@@ -380,6 +387,7 @@
if (mCondition) {
if (allData.size() == 0) {
VLOG("Data pulled is empty");
+ StatsdStats::getInstance().noteEmptyData(mPullTagId);
return;
}
// For scheduled pulled data, the effective event time is snap to the nearest
@@ -394,6 +402,7 @@
if (bucketEndTime < mCurrentBucketStartTimeNs) {
VLOG("Skip bucket end pull due to late arrival: %lld vs %lld", (long long)bucketEndTime,
(long long)mCurrentBucketStartTimeNs);
+ StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
return;
}
for (const auto& data : allData) {
@@ -442,6 +451,7 @@
if (newTupleCount > mDimensionHardLimit) {
ALOGE("ValueMetric %lld dropping data for dimension key %s", (long long)mMetricId,
newKey.toString().c_str());
+ StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
return true;
}
}
@@ -539,6 +549,7 @@
Value value;
if (!getDoubleOrLong(event, matcher, value)) {
VLOG("Failed to get value %d from event %s", i, event.ToString().c_str());
+ StatsdStats::getInstance().noteBadValueType(mMetricId);
return;
}
interval.seenNewData = true;
@@ -656,6 +667,7 @@
if (numBucketsForward > 1) {
VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
+ StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
// take base again in future good bucket.
resetBase();
}
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index e8de875..cca09ac 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -403,9 +403,23 @@
optional int64 data_error = 9;
optional int64 pull_timeout = 10;
optional int64 pull_exceed_max_delay = 11;
+ optional int64 pull_failed = 12;
+ optional int64 stats_companion_pull_failed = 13;
+ optional int64 stats_companion_pull_binder_transaction_failed = 14;
+ optional int64 empty_data = 15;
}
repeated PulledAtomStats pulled_atom_stats = 10;
+ message AtomMetricStats {
+ optional int64 metric_id = 1;
+ optional int64 hard_dimension_limit_reached = 2;
+ optional int64 late_log_event_skipped = 3;
+ optional int64 skipped_forward_buckets = 4;
+ optional int64 bad_value_type = 5;
+ optional int64 condition_change_in_next_bucket = 6;
+ }
+ repeated AtomMetricStats atom_metric_stats = 17;
+
message LoggerErrorStats {
optional int32 logger_disconnection_sec = 1;
optional int32 error_code = 2;
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 7de0bb3..9c9985e 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -66,6 +66,18 @@
const int FIELD_ID_DATA_ERROR = 9;
const int FIELD_ID_PULL_TIMEOUT = 10;
const int FIELD_ID_PULL_EXCEED_MAX_DELAY = 11;
+const int FIELD_ID_PULL_FAILED = 12;
+const int FIELD_ID_STATS_COMPANION_FAILED = 13;
+const int FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED = 14;
+const int FIELD_ID_EMPTY_DATA = 15;
+// for AtomMetricStats proto
+const int FIELD_ID_ATOM_METRIC_STATS = 17;
+const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_HARD_DIMENSION_LIMIT_REACHED = 2;
+const int FIELD_ID_LATE_LOG_EVENT_SKIPPED = 3;
+const int FIELD_ID_SKIPPED_FORWARD_BUCKETS = 4;
+const int FIELD_ID_BAD_VALUE_TYPE = 5;
+const int FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET = 6;
namespace {
@@ -456,6 +468,32 @@
(long long)pair.second.pullTimeout);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_EXCEED_MAX_DELAY,
(long long)pair.second.pullExceedMaxDelay);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_FAILED,
+ (long long)pair.second.pullFailed);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_STATS_COMPANION_FAILED,
+ (long long)pair.second.statsCompanionPullFailed);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED,
+ (long long)pair.second.statsCompanionPullBinderTransactionFailed);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA,
+ (long long)pair.second.emptyData);
+ protoOutput->end(token);
+}
+
+void writeAtomMetricStatsToStream(const std::pair<int, StatsdStats::AtomMetricStats> &pair,
+ util::ProtoOutputStream *protoOutput) {
+ uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_METRIC_STATS |
+ FIELD_COUNT_REPEATED);
+ protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, (int32_t)pair.first);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_HARD_DIMENSION_LIMIT_REACHED,
+ (long long)pair.second.hardDimensionLimitReached);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_LATE_LOG_EVENT_SKIPPED,
+ (long long)pair.second.lateLogEventSkipped);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_FORWARD_BUCKETS,
+ (long long)pair.second.skippedForwardBuckets);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BAD_VALUE_TYPE,
+ (long long)pair.second.badValueType);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET,
+ (long long)pair.second.conditionChangeInNextBucket);
protoOutput->end(token);
}
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index 61f31eb..dcea0e6 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -73,6 +73,10 @@
void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
util::ProtoOutputStream* protoOutput);
+// Helper function to write AtomMetricStats to ProtoOutputStream
+void writeAtomMetricStatsToStream(const std::pair<int, StatsdStats::AtomMetricStats> &pair,
+ util::ProtoOutputStream *protoOutput);
+
template<class T>
bool parseProtoOutputStream(util::ProtoOutputStream& protoOutput, T* message) {
std::string pbBytes;
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 8e7a58b..a748959 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1942,7 +1942,6 @@
Lcom/android/internal/R$id;->titleDivider:I
Lcom/android/internal/R$id;->titleDividerTop:I
Lcom/android/internal/R$id;->title_container:I
-Lcom/android/internal/R$id;->title_icon:I
Lcom/android/internal/R$id;->title_template:I
Lcom/android/internal/R$id;->topPanel:I
Lcom/android/internal/R$id;->up:I
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index ce5d8a5..eae7d6b 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -28,15 +28,12 @@
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
-import android.hardware.input.InputManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.IWindowManager;
-import android.view.InputDevice;
-import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceSession;
@@ -51,9 +48,7 @@
import java.util.List;
/**
- * Activity container that allows launching activities into itself and does input forwarding.
- * <p>Creation of this view is only allowed to callers who have
- * {@link android.Manifest.permission#INJECT_EVENTS} permission.
+ * Activity container that allows launching activities into itself.
* <p>Activity launching into this container is restricted by the same rules that apply to launching
* on VirtualDisplays.
* @hide
@@ -76,9 +71,8 @@
private StateCallback mActivityViewCallback;
private IActivityTaskManager mActivityTaskManager;
- private IInputForwarder mInputForwarder;
- // Temp container to store view coordinates on screen.
- private final int[] mLocationOnScreen = new int[2];
+ // Temp container to store view coordinates in window.
+ private final int[] mLocationInWindow = new int[2];
private TaskStackListener mTaskStackListener;
@@ -280,7 +274,7 @@
}
/**
- * Triggers an update of {@link ActivityView}'s location on screen to properly set touch exclude
+ * Triggers an update of {@link ActivityView}'s location in window to properly set touch exclude
* regions and avoid focus switches by touches on this view.
*/
public void onLocationChanged() {
@@ -295,45 +289,14 @@
/** Send current location and size to the WM to set tap exclude region for this view. */
private void updateLocation() {
try {
- getLocationOnScreen(mLocationOnScreen);
+ getLocationInWindow(mLocationInWindow);
WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
- mLocationOnScreen[0], mLocationOnScreen[1], getWidth(), getHeight());
+ mLocationInWindow[0], mLocationInWindow[1], getWidth(), getHeight());
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return injectInputEvent(event) || super.onTouchEvent(event);
- }
-
- @Override
- public boolean onGenericMotionEvent(MotionEvent event) {
- if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
- if (injectInputEvent(event)) {
- return true;
- }
- }
- return super.onGenericMotionEvent(event);
- }
-
- private boolean injectInputEvent(MotionEvent event) {
- if (mInputForwarder != null) {
- try {
- // The touch event that the ActivityView gets is in View space, but the event needs
- // to get forwarded in screen space. This offsets the touch event by the location
- // the ActivityView is on screen and sends it to the input forwarder.
- getLocationOnScreen(mLocationOnScreen);
- event.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
- return mInputForwarder.forwardEvent(event);
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
- }
- return false;
- }
-
private class SurfaceCallback implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
@@ -416,7 +379,6 @@
}
mTmpTransaction.show(mRootSurfaceControl).apply();
- mInputForwarder = InputManager.getInstance().createInputForwarder(displayId);
mTaskStackListener = new TaskStackListenerImpl();
try {
mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
@@ -432,9 +394,6 @@
mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
- if (mInputForwarder != null) {
- mInputForwarder = null;
- }
cleanTapExcludeRegion();
if (mTaskStackListener != null) {
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 8953940..ec78428 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -65,6 +65,9 @@
boolean areNotificationsEnabled(String pkg);
int getPackageImportance(String pkg);
+ boolean shouldHideSilentStatusIcons(String callingPkg);
+ void setHideSilentStatusIcons(boolean hide);
+
void setBubblesAllowed(String pkg, int uid, boolean allowed);
boolean areBubblesAllowed(String pkg);
boolean areBubblesAllowedForPackage(String pkg, int uid);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 621f134..587b591 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -353,7 +354,8 @@
public static final int IMPORTANCE_MIN = 1;
/**
- * Low notification importance: shows everywhere, but is not intrusive.
+ * Low notification importance: Shows in the shade, and potentially in the status bar
+ * (see {@link #shouldHideSilentStatusBarIcons()}), but is not audibly intrusive.
*/
public static final int IMPORTANCE_LOW = 2;
@@ -1162,6 +1164,22 @@
}
}
+ /**
+ * Returns whether the user wants silent notifications (see {@link #IMPORTANCE_LOW} to appear
+ * in the status bar.
+ *
+ * <p>Only available for {@link #isNotificationListenerAccessGranted(ComponentName) notification
+ * listeners}.
+ */
+ public boolean shouldHideSilentStatusBarIcons() {
+ INotificationManager service = getService();
+ try {
+ return service.shouldHideSilentStatusIcons(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @hide */
public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
INotificationManager service = getService();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 65ea635..a3021f3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -971,7 +971,8 @@
*
* @param target The Intent that the user will be selecting an activity
* to perform.
- * @param title Optional title that will be displayed in the chooser.
+ * @param title Optional title that will be displayed in the chooser,
+ * only when the target action is not ACTION_SEND or ACTION_SEND_MULTIPLE.
* @return Return a new Intent object that you can hand to
* {@link Context#startActivity(Intent) Context.startActivity()} and
* related methods.
@@ -998,7 +999,8 @@
*
* @param target The Intent that the user will be selecting an activity
* to perform.
- * @param title Optional title that will be displayed in the chooser.
+ * @param title Optional title that will be displayed in the chooser,
+ * only when the target action is not ACTION_SEND or ACTION_SEND_MULTIPLE.
* @param sender Optional IntentSender to be called when a choice is made.
* @return Return a new Intent object that you can hand to
* {@link Context#startActivity(Intent) Context.startActivity()} and
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 4644a83..d4ed35a 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -16,10 +16,14 @@
package android.content.rollback;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.pm.VersionedPackage;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.IntArray;
+
+import java.util.ArrayList;
/**
* Information about a rollback available for a particular package.
@@ -33,6 +37,38 @@
private final VersionedPackage mVersionRolledBackTo;
/**
+ * Encapsulates information required to restore a snapshot of an app's userdata.
+ *
+ * @hide
+ */
+ public static class RestoreInfo {
+ public final int userId;
+ public final int appId;
+ public final String seInfo;
+
+ public RestoreInfo(int userId, int appId, String seInfo) {
+ this.userId = userId;
+ this.appId = appId;
+ this.seInfo = seInfo;
+ }
+ }
+
+ /*
+ * The list of users for which we need to backup userdata for this package. Backups of
+ * credential encrypted data are listed as pending if the user hasn't unlocked their device
+ * with credentials yet.
+ */
+ // NOTE: Not a part of the Parcelable representation of this object.
+ private final IntArray mPendingBackups;
+
+ /**
+ * The list of users for which we need to restore userdata for this package. This field is
+ * non-null only after a rollback for this package has been committed.
+ */
+ // NOTE: Not a part of the Parcelable representation of this object.
+ private final ArrayList<RestoreInfo> mPendingRestores;
+
+ /**
* Returns the name of the package to roll back from.
*/
public String getPackageName() {
@@ -54,15 +90,46 @@
}
/** @hide */
+ public IntArray getPendingBackups() {
+ return mPendingBackups;
+ }
+
+ /** @hide */
+ public ArrayList<RestoreInfo> getPendingRestores() {
+ return mPendingRestores;
+ }
+
+ /** @hide */
+ public RestoreInfo getRestoreInfo(int userId) {
+ for (RestoreInfo ri : mPendingRestores) {
+ if (ri.userId == userId) {
+ return ri;
+ }
+ }
+
+ return null;
+ }
+
+ /** @hide */
+ public void removeRestoreInfo(RestoreInfo ri) {
+ mPendingRestores.remove(ri);
+ }
+
+ /** @hide */
public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
- VersionedPackage packageRolledBackTo) {
+ VersionedPackage packageRolledBackTo,
+ @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores) {
this.mVersionRolledBackFrom = packageRolledBackFrom;
this.mVersionRolledBackTo = packageRolledBackTo;
+ this.mPendingBackups = pendingBackups;
+ this.mPendingRestores = pendingRestores;
}
private PackageRollbackInfo(Parcel in) {
this.mVersionRolledBackFrom = VersionedPackage.CREATOR.createFromParcel(in);
this.mVersionRolledBackTo = VersionedPackage.CREATOR.createFromParcel(in);
+ this.mPendingRestores = null;
+ this.mPendingBackups = null;
}
@Override
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 1111b43..3fd2476 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -83,7 +83,7 @@
* Returns the session ID for the committed rollback for staged rollbacks.
* Only applicable for rollbacks that have been committed.
*/
- public int getSessionId() {
+ public int getCommittedSessionId() {
// TODO: Support rollback of staged installs.
return PackageInstaller.SessionInfo.INVALID_ID;
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3bae12e..ef8ca9e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2918,11 +2918,11 @@
}
}
- /** {@hide} */
+ /** {@hide} - returns the factory serial number */
@UnsupportedAppUsage
- public void registerNetworkFactory(Messenger messenger, String name) {
+ public int registerNetworkFactory(Messenger messenger, String name) {
try {
- mService.registerNetworkFactory(messenger, name);
+ return mService.registerNetworkFactory(messenger, name);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2938,6 +2938,10 @@
}
}
+ // TODO : remove this method. It is a stopgap measure to help sheperding a number
+ // of dependent changes that would conflict throughout the automerger graph. Having this
+ // temporarily helps with the process of going through with all these dependent changes across
+ // the entire tree.
/**
* @hide
* Register a NetworkAgent with ConnectivityService.
@@ -2945,8 +2949,20 @@
*/
public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkMisc misc) {
+ return registerNetworkAgent(messenger, ni, lp, nc, score, misc,
+ NetworkFactory.SerialNumber.NONE);
+ }
+
+ /**
+ * @hide
+ * Register a NetworkAgent with ConnectivityService.
+ * @return NetID corresponding to NetworkAgent.
+ */
+ public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+ NetworkCapabilities nc, int score, NetworkMisc misc, int factorySerialNumber) {
try {
- return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
+ return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc,
+ factorySerialNumber);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index fd7360f..f88adc2 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -139,14 +139,14 @@
void setAirplaneMode(boolean enable);
- void registerNetworkFactory(in Messenger messenger, in String name);
+ int registerNetworkFactory(in Messenger messenger, in String name);
boolean requestBandwidthUpdate(in Network network);
void unregisterNetworkFactory(in Messenger messenger);
int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
- in NetworkCapabilities nc, int score, in NetworkMisc misc);
+ in NetworkCapabilities nc, int score, in NetworkMisc misc, in int factorySerialNumber);
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy);
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 99bfc14..204c25f 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -58,6 +58,7 @@
private static final long BW_REFRESH_MIN_WIN_MS = 500;
private boolean mPollLceScheduled = false;
private AtomicBoolean mPollLcePending = new AtomicBoolean(false);
+ public final int mFactorySerialNumber;
private static final int BASE = Protocol.BASE_NETWORK_AGENT;
@@ -193,16 +194,31 @@
*/
public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
+ // TODO : remove these two constructors. They are a stopgap measure to help sheperding a number
+ // of dependent changes that would conflict throughout the automerger graph. Having these
+ // temporarily helps with the process of going through with all these dependent changes across
+ // the entire tree.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score) {
- this(looper, context, logTag, ni, nc, lp, score, null);
+ this(looper, context, logTag, ni, nc, lp, score, null, NetworkFactory.SerialNumber.NONE);
+ }
+ public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
+ NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
+ this(looper, context, logTag, ni, nc, lp, score, misc, NetworkFactory.SerialNumber.NONE);
}
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
- NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
+ NetworkCapabilities nc, LinkProperties lp, int score, int factorySerialNumber) {
+ this(looper, context, logTag, ni, nc, lp, score, null, factorySerialNumber);
+ }
+
+ public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
+ NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc,
+ int factorySerialNumber) {
super(looper);
LOG_TAG = logTag;
mContext = context;
+ mFactorySerialNumber = factorySerialNumber;
if (ni == null || nc == null || lp == null) {
throw new IllegalArgumentException();
}
@@ -211,7 +227,8 @@
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
- new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
+ new LinkProperties(lp), new NetworkCapabilities(nc), score, misc,
+ factorySerialNumber);
}
@Override
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 181cab4..0dfe7a4 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -32,6 +32,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* A NetworkFactory is an entity that creates NetworkAgent objects.
@@ -49,6 +50,20 @@
* @hide
**/
public class NetworkFactory extends Handler {
+ /** @hide */
+ public static class SerialNumber {
+ // Guard used by no network factory.
+ public static final int NONE = -1;
+ // A hardcoded serial number for NetworkAgents representing VPNs. These agents are
+ // not created by any factory, so they use this constant for clarity instead of NONE.
+ public static final int VPN = -2;
+ private static final AtomicInteger sNetworkFactorySerialNumber = new AtomicInteger(1);
+ /** Returns a unique serial number for a factory. */
+ public static final int nextSerialNumber() {
+ return sNetworkFactorySerialNumber.getAndIncrement();
+ }
+ }
+
private static final boolean DBG = true;
private static final boolean VDBG = false;
@@ -64,7 +79,7 @@
* disregard any that it will never be able to service, for example
* those requiring a different bearer.
* msg.obj = NetworkRequest
- * msg.arg1 = score - the score of the any network currently satisfying this
+ * msg.arg1 = score - the score of the network currently satisfying this
* request. If this bearer knows in advance it cannot
* exceed this score it should not try to connect, holding the request
* for the future.
@@ -74,6 +89,8 @@
* with the same NetworkRequest but an updated score.
* Also, network conditions may change for this bearer
* allowing for a better score in the future.
+ * msg.arg2 = the serial number of the factory currently responsible for the
+ * NetworkAgent handling this request, or SerialNumber.NONE if none.
*/
public static final int CMD_REQUEST_NETWORK = BASE;
@@ -107,6 +124,7 @@
private int mRefCount = 0;
private Messenger mMessenger = null;
+ private int mSerialNumber;
@UnsupportedAppUsage
public NetworkFactory(Looper looper, Context context, String logTag,
@@ -121,7 +139,8 @@
if (DBG) log("Registering NetworkFactory");
if (mMessenger == null) {
mMessenger = new Messenger(this);
- ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
+ mSerialNumber = ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger,
+ LOG_TAG);
}
}
@@ -137,7 +156,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case CMD_REQUEST_NETWORK: {
- handleAddRequest((NetworkRequest)msg.obj, msg.arg1);
+ handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
break;
}
case CMD_CANCEL_REQUEST: {
@@ -159,11 +178,13 @@
public final NetworkRequest request;
public int score;
public boolean requested; // do we have a request outstanding, limited by score
+ public int factorySerialNumber;
- public NetworkRequestInfo(NetworkRequest request, int score) {
+ NetworkRequestInfo(NetworkRequest request, int score, int factorySerialNumber) {
this.request = request;
this.score = score;
this.requested = false;
+ this.factorySerialNumber = factorySerialNumber;
}
@Override
@@ -172,16 +193,51 @@
}
}
+ /**
+ * Add a NetworkRequest that the bearer may want to attempt to satisfy.
+ * @see #CMD_REQUEST_NETWORK
+ *
+ * @param request the request to handle.
+ * @param score the score of the NetworkAgent currently satisfying this request.
+ * @param servingFactorySerialNumber the serial number of the NetworkFactory that
+ * created the NetworkAgent currently satisfying this request.
+ */
+ // TODO : remove this method. It is a stopgap measure to help sheperding a number
+ // of dependent changes that would conflict throughout the automerger graph. Having this
+ // temporarily helps with the process of going through with all these dependent changes across
+ // the entire tree.
@VisibleForTesting
protected void handleAddRequest(NetworkRequest request, int score) {
+ handleAddRequest(request, score, SerialNumber.NONE);
+ }
+
+ /**
+ * Add a NetworkRequest that the bearer may want to attempt to satisfy.
+ * @see #CMD_REQUEST_NETWORK
+ *
+ * @param request the request to handle.
+ * @param score the score of the NetworkAgent currently satisfying this request.
+ * @param servingFactorySerialNumber the serial number of the NetworkFactory that
+ * created the NetworkAgent currently satisfying this request.
+ */
+ @VisibleForTesting
+ protected void handleAddRequest(NetworkRequest request, int score,
+ int servingFactorySerialNumber) {
NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
if (n == null) {
- if (DBG) log("got request " + request + " with score " + score);
- n = new NetworkRequestInfo(request, score);
+ if (DBG) {
+ log("got request " + request + " with score " + score
+ + " and serial " + servingFactorySerialNumber);
+ }
+ n = new NetworkRequestInfo(request, score, servingFactorySerialNumber);
mNetworkRequests.put(n.request.requestId, n);
} else {
- if (VDBG) log("new score " + score + " for exisiting request " + request);
+ if (VDBG) {
+ log("new score " + score + " for exisiting request " + request
+ + " with serial " + servingFactorySerialNumber);
+ }
n.score = score;
+ n.factorySerialNumber = servingFactorySerialNumber;
}
if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter);
@@ -231,16 +287,19 @@
}
private void evalRequest(NetworkRequestInfo n) {
- if (VDBG) log("evalRequest");
- if (n.requested == false && n.score < mScore &&
- n.request.networkCapabilities.satisfiedByNetworkCapabilities(
- mCapabilityFilter) && acceptRequest(n.request, n.score)) {
+ if (VDBG) {
+ log("evalRequest");
+ log(" n.requests = " + n.requested);
+ log(" n.score = " + n.score);
+ log(" mScore = " + mScore);
+ log(" n.factorySerialNumber = " + n.factorySerialNumber);
+ log(" mSerialNumber = " + mSerialNumber);
+ }
+ if (shouldNeedNetworkFor(n)) {
if (VDBG) log(" needNetworkFor");
needNetworkFor(n.request, n.score);
n.requested = true;
- } else if (n.requested == true &&
- (n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities(
- mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false)) {
+ } else if (shouldReleaseNetworkFor(n)) {
if (VDBG) log(" releaseNetworkFor");
releaseNetworkFor(n.request);
n.requested = false;
@@ -249,10 +308,39 @@
}
}
+ private boolean shouldNeedNetworkFor(NetworkRequestInfo n) {
+ // If this request is already tracked, it doesn't qualify for need
+ return !n.requested
+ // If the score of this request is higher or equal to that of this factory and some
+ // other factory is responsible for it, then this factory should not track the request
+ // because it has no hope of satisfying it.
+ && (n.score < mScore || n.factorySerialNumber == mSerialNumber)
+ // If this factory can't satisfy the capability needs of this request, then it
+ // should not be tracked.
+ && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter)
+ // Finally if the concrete implementation of the factory rejects the request, then
+ // don't track it.
+ && acceptRequest(n.request, n.score);
+ }
+
+ private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) {
+ // Don't release a request that's not tracked.
+ return n.requested
+ // The request should be released if it can't be satisfied by this factory. That
+ // means either of the following conditions are met :
+ // - Its score is too high to be satisfied by this factory and it's not already
+ // assigned to the factory
+ // - This factory can't satisfy the capability needs of the request
+ // - The concrete implementation of the factory rejects the request
+ && ((n.score > mScore && n.factorySerialNumber != mSerialNumber)
+ || !n.request.networkCapabilities.satisfiedByNetworkCapabilities(
+ mCapabilityFilter)
+ || !acceptRequest(n.request, n.score));
+ }
+
private void evalRequests() {
for (int i = 0; i < mNetworkRequests.size(); i++) {
NetworkRequestInfo n = mNetworkRequests.valueAt(i);
-
evalRequest(n);
}
}
@@ -280,16 +368,6 @@
if (--mRefCount == 0) stopNetwork();
}
-
- public void addNetworkRequest(NetworkRequest networkRequest, int score) {
- sendMessage(obtainMessage(CMD_REQUEST_NETWORK,
- new NetworkRequestInfo(networkRequest, score)));
- }
-
- public void removeNetworkRequest(NetworkRequest networkRequest) {
- sendMessage(obtainMessage(CMD_CANCEL_REQUEST, networkRequest));
- }
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setScoreFilter(int score) {
sendMessage(obtainMessage(CMD_SET_SCORE, score, 0));
@@ -304,6 +382,10 @@
return mNetworkRequests.size();
}
+ public int getSerialNumber() {
+ return mSerialNumber;
+ }
+
protected void log(String s) {
Log.d(LOG_TAG, s);
}
@@ -321,10 +403,11 @@
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - ScoreFilter=").
- append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=").
- append(mNetworkRequests.size()).append(", refCount=").append(mRefCount).
- append("}");
+ StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mSerialNumber=")
+ .append(mSerialNumber).append(", ScoreFilter=")
+ .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=")
+ .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount)
+ .append("}");
return sb.toString();
}
}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 8a52f1f..3e5bd4b 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -138,8 +138,8 @@
* Action used to help apps show calendar events in the managed profile.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_VIEW_WORK_CALENDAR_EVENT =
- "android.provider.calendar.action.VIEW_WORK_CALENDAR_EVENT";
+ public static final String ACTION_VIEW_MANAGED_PROFILE_CALENDAR_EVENT =
+ "android.provider.calendar.action.VIEW_MANAGED_PROFILE_CALENDAR_EVENT";
/**
* Intent Extras key: {@link EventsColumns#CUSTOM_APP_URI} for the event in
@@ -166,7 +166,7 @@
public static final String EXTRA_EVENT_ALL_DAY = "allDay";
/**
- * Intent Extras key: The id of an event.
+ * Intent Extras key: An extra of type {@code long} holding the id of an event.
*/
public static final String EXTRA_EVENT_ID = "id";
@@ -218,7 +218,7 @@
* When this API is called, the system will attempt to start an activity
* in the managed profile with an intent targeting the same caller package.
* The intent will have its action set to
- * {@link CalendarContract#ACTION_VIEW_WORK_CALENDAR_EVENT} and contain extras
+ * {@link CalendarContract#ACTION_VIEW_MANAGED_PROFILE_CALENDAR_EVENT} and contain extras
* corresponding to the API's arguments. A calendar app intending to support
* cross-profile events viewing should handle this intent, parse the arguments
* and show the appropriate UI.
@@ -226,10 +226,10 @@
* @param context the context.
* @param eventId the id of the event to be viewed. Will be put into {@link #EXTRA_EVENT_ID}
* field of the intent.
- * @param start the start time of the event. Will be put into {@link #EXTRA_EVENT_BEGIN_TIME}
- * field of the intent.
- * @param end the end time of the event. Will be put into {@link #EXTRA_EVENT_END_TIME} field
- * of the intent.
+ * @param startMs the start time of the event in milliseconds since epoch.
+ * Will be put into {@link #EXTRA_EVENT_BEGIN_TIME} field of the intent.
+ * @param endMs the end time of the event in milliseconds since epoch.
+ * Will be put into {@link #EXTRA_EVENT_END_TIME} field of the intent.
* @param allDay if the event is an all-day event. Will be put into
* {@link #EXTRA_EVENT_ALL_DAY} field of the intent.
* @param flags flags to be set on the intent via {@link Intent#setFlags}
@@ -241,12 +241,12 @@
* @see #EXTRA_EVENT_ALL_DAY
*/
public static boolean startViewCalendarEventInManagedProfile(@NonNull Context context,
- long eventId, long start, long end, boolean allDay, int flags) {
+ long eventId, long startMs, long endMs, boolean allDay, int flags) {
Preconditions.checkNotNull(context, "Context is null");
final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
- return dpm.startViewCalendarEventInManagedProfile(eventId, start,
- end, allDay, flags);
+ return dpm.startViewCalendarEventInManagedProfile(eventId, startMs,
+ endMs, allDay, flags);
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 794c2f1..5151e29 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10521,8 +10521,10 @@
/**
* Setting to enable connected MAC randomization in Wi-Fi; disabled by default, and
* setting to 1 will enable it. In the future, additional values may be supported.
+ * @deprecated MAC randomization is now a per-network setting
* @hide
*/
+ @Deprecated
public static final String WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED =
"wifi_connected_mac_randomization_enabled";
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 1ddc099e..22104b5 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -33,6 +33,7 @@
void onListenerConnected(in NotificationRankingUpdate update);
void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update);
+ void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons);
// stats only for assistant
void onNotificationRemoved(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update, in NotificationStats stats, int reason);
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index c734b63..d4e8879 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -469,6 +469,17 @@
}
/**
+ * Implement this method to be notified when the behavior of silent notifications in the status
+ * bar changes. See {@link NotificationManager#shouldHideSilentStatusBarIcons()}.
+ *
+ * @param hideSilentStatusIcons whether or not status bar icons should be hidden for silent
+ * notifications
+ */
+ public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+ // optional
+ }
+
+ /**
* Implement this method to learn about notification channel modifications.
*
* <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated
@@ -1411,6 +1422,12 @@
mHandler.obtainMessage(
MyHandler.MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED, args).sendToTarget();
}
+
+ @Override
+ public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_STATUS_BAR_ICON_BEHAVIOR_CHANGED,
+ hideSilentStatusIcons).sendToTarget();
+ }
}
/**
@@ -2142,6 +2159,7 @@
public static final int MSG_ON_INTERRUPTION_FILTER_CHANGED = 6;
public static final int MSG_ON_NOTIFICATION_CHANNEL_MODIFIED = 7;
public static final int MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED = 8;
+ public static final int MSG_ON_STATUS_BAR_ICON_BEHAVIOR_CHANGED = 9;
public MyHandler(Looper looper) {
super(looper, null, false);
@@ -2207,6 +2225,10 @@
int modificationType = (int) args.arg4;
onNotificationChannelGroupModified(pkgName, user, group, modificationType);
} break;
+
+ case MSG_ON_STATUS_BAR_ICON_BEHAVIOR_CHANGED: {
+ onStatusBarIconsBehaviorChanged((Boolean) msg.obj);
+ } break;
}
}
}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index eb41e07..59e562f 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -41,12 +41,14 @@
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityRequestPreparer;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
@@ -64,8 +66,11 @@
* called from the interaction connection ViewAncestor gives the system to
* talk to it and a corresponding *UiThread method that is executed on the
* UI thread.
+ *
+ * @hide
*/
-final class AccessibilityInteractionController {
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public final class AccessibilityInteractionController {
private static final String LOG_TAG = "AccessibilityInteractionController";
@@ -85,7 +90,7 @@
private final Object mLock = new Object();
- private final Handler mHandler;
+ private final PrivateHandler mHandler;
private final ViewRootImpl mViewRootImpl;
@@ -131,11 +136,19 @@
// thread in this process, set the message as a static reference so
// after this call completes the same thread but in the interrogating
// client can handle the message to generate the result.
- if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId) {
+ if (interrogatingPid == mMyProcessId && interrogatingTid == mMyLooperThreadId
+ && mHandler.hasAccessibilityCallback(message)) {
AccessibilityInteractionClient.getInstanceForThread(
interrogatingTid).setSameThreadMessage(message);
} else {
- mHandler.sendMessage(message);
+ // For messages without callback of interrogating client, just handle the
+ // message immediately if this is UI thread.
+ if (!mHandler.hasAccessibilityCallback(message)
+ && Thread.currentThread().getId() == mMyLooperThreadId) {
+ mHandler.handleMessage(message);
+ } else {
+ mHandler.sendMessage(message);
+ }
}
}
}
@@ -731,6 +744,52 @@
}
}
+ /**
+ * Finds the accessibility focused node in the root, and clears the accessibility focus.
+ */
+ public void clearAccessibilityFocusClientThread() {
+ final Message message = mHandler.obtainMessage();
+ message.what = PrivateHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS;
+
+ // Don't care about pid and tid because there's no interrogating client for this message.
+ scheduleMessage(message, 0, 0, CONSIDER_REQUEST_PREPARERS);
+ }
+
+ private void clearAccessibilityFocusUiThread() {
+ if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
+ return;
+ }
+ try {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags =
+ AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
+ final View root = mViewRootImpl.mView;
+ if (root != null && isShown(root)) {
+ final View host = mViewRootImpl.mAccessibilityFocusedHost;
+ // If there is no accessibility focus host or it is not a descendant
+ // of the root from which to start the search, then the search failed.
+ if (host == null || !ViewRootImpl.isViewDescendantOf(host, root)) {
+ return;
+ }
+ final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
+ final AccessibilityNodeInfo focusNode =
+ mViewRootImpl.mAccessibilityFocusedVirtualView;
+ if (provider != null && focusNode != null) {
+ final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
+ focusNode.getSourceNodeId());
+ provider.performAction(virtualNodeId,
+ AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(),
+ null);
+ } else {
+ host.performAccessibilityAction(
+ AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(),
+ null);
+ }
+ }
+ } finally {
+ mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+ }
+ }
+
private View findViewByAccessibilityId(int accessibilityId) {
View root = mViewRootImpl.mView;
if (root == null) {
@@ -1294,6 +1353,12 @@
private static final int MSG_APP_PREPARATION_FINISHED = 8;
private static final int MSG_APP_PREPARATION_TIMEOUT = 9;
+ // Uses FIRST_NO_ACCESSIBILITY_CALLBACK_MSG for messages that don't need to call back
+ // results to interrogating client.
+ private static final int FIRST_NO_ACCESSIBILITY_CALLBACK_MSG = 100;
+ private static final int MSG_CLEAR_ACCESSIBILITY_FOCUS =
+ FIRST_NO_ACCESSIBILITY_CALLBACK_MSG + 1;
+
public PrivateHandler(Looper looper) {
super(looper);
}
@@ -1320,6 +1385,8 @@
return "MSG_APP_PREPARATION_FINISHED";
case MSG_APP_PREPARATION_TIMEOUT:
return "MSG_APP_PREPARATION_TIMEOUT";
+ case MSG_CLEAR_ACCESSIBILITY_FOCUS:
+ return "MSG_CLEAR_ACCESSIBILITY_FOCUS";
default:
throw new IllegalArgumentException("Unknown message type: " + type);
}
@@ -1356,10 +1423,17 @@
case MSG_APP_PREPARATION_TIMEOUT: {
requestPreparerTimeoutUiThread();
} break;
+ case MSG_CLEAR_ACCESSIBILITY_FOCUS: {
+ clearAccessibilityFocusUiThread();
+ } break;
default:
throw new IllegalArgumentException("Unknown message type: " + type);
}
}
+
+ boolean hasAccessibilityCallback(Message message) {
+ return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false;
+ }
}
private final class AddNodeInfosForViewId implements Predicate<View> {
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 92e0009..ec79eea 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -16,10 +16,10 @@
package android.view;
+import static android.view.Display.INVALID_DISPLAY;
+
import android.graphics.Region;
import android.os.IBinder;
-import android.view.IWindow;
-import android.view.InputChannel;
/**
* Functions as a handle for a window that can receive input.
@@ -94,6 +94,10 @@
// Display this input is on.
public int displayId;
+ // If this value is set to a valid display ID, it indicates this window is a portal which
+ // transports the touch of this window to the display indicated by portalToDisplayId.
+ public int portalToDisplayId = INVALID_DISPLAY;
+
private native void nativeDispose();
public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f47eb10..9213f32 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8718,6 +8718,15 @@
}
}
}
+
+ @Override
+ public void clearAccessibilityFocus() {
+ ViewRootImpl viewRootImpl = mViewRootImpl.get();
+ if (viewRootImpl != null && viewRootImpl.mView != null) {
+ viewRootImpl.getAccessibilityInteractionController()
+ .clearAccessibilityFocusClientThread();
+ }
+ }
}
private class SendWindowContentChangedAccessibilityEvent implements Runnable {
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index 4c0fdfd..947ff05 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -55,4 +55,6 @@
void performAccessibilityAction(long accessibilityNodeId, int action, in Bundle arguments,
int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
int interrogatingPid, long interrogatingTid);
+
+ void clearAccessibilityFocus();
}
diff --git a/core/java/android/view/contentcapture/UserDataRemovalRequest.java b/core/java/android/view/contentcapture/UserDataRemovalRequest.java
index 8ee63ef..8fedcd5 100644
--- a/core/java/android/view/contentcapture/UserDataRemovalRequest.java
+++ b/core/java/android/view/contentcapture/UserDataRemovalRequest.java
@@ -16,7 +16,6 @@
package android.view.contentcapture;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.net.Uri;
import android.os.Parcel;
@@ -67,9 +66,7 @@
/**
* Gets the name of the app that's making the request.
- * @hide
*/
- @SystemApi
@NonNull
public String getPackageName() {
return mPackageName;
@@ -77,20 +74,14 @@
/**
* Checks if app is requesting to remove all user data associated with its package.
- *
- * @hide
*/
- @SystemApi
public boolean isForEverything() {
return mForEverything;
}
/**
* Gets the list of {@code Uri}s the apps is requesting to remove.
- *
- * @hide
*/
- @SystemApi
@NonNull
public List<UriRequest> getUriRequests() {
return mUriRequests;
@@ -203,9 +194,7 @@
/**
* Representation of a request to remove data associated with an {@link Uri}.
- * @hide
*/
- @SystemApi
public final class UriRequest {
private final @NonNull Uri mUri;
private final boolean mRecursive;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 299801a..46f42f7 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -24,6 +24,7 @@
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
+import android.content.ClipData;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -41,9 +42,13 @@
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.database.DataSetObserver;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
@@ -62,7 +67,9 @@
import android.service.chooser.IChooserTargetResult;
import android.service.chooser.IChooserTargetService;
import android.text.TextUtils;
+import android.util.AttributeSet;
import android.util.Log;
+import android.util.Size;
import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
@@ -73,9 +80,11 @@
import android.view.ViewGroup.LayoutParams;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Space;
+import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -85,6 +94,7 @@
import com.google.android.collect.Lists;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -262,16 +272,31 @@
}
mReplacementExtras = intent.getBundleExtra(Intent.EXTRA_REPLACEMENT_EXTRAS);
- CharSequence title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE);
+
+ // Do not allow the title to be changed when sharing content
+ CharSequence title = null;
+ if (target != null) {
+ String targetAction = target.getAction();
+ if (!(Intent.ACTION_SEND.equals(targetAction) || Intent.ACTION_SEND_MULTIPLE.equals(
+ targetAction))) {
+ title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE);
+ } else {
+ Log.w(TAG, "Ignoring intent's EXTRA_TITLE, deprecated in P. You may wish to set a"
+ + " preview title by using EXTRA_TITLE property of the wrapped"
+ + " EXTRA_INTENT.");
+ }
+ }
+
int defaultTitleRes = 0;
if (title == null) {
defaultTitleRes = com.android.internal.R.string.chooseActivity;
}
+
Parcelable[] pa = intent.getParcelableArrayExtra(Intent.EXTRA_INITIAL_INTENTS);
Intent[] initialIntents = null;
if (pa != null) {
initialIntents = new Intent[pa.length];
- for (int i=0; i<pa.length; i++) {
+ for (int i = 0; i < pa.length; i++) {
if (!(pa[i] instanceof Intent)) {
Log.w(TAG, "Initial intent #" + i + " not an Intent: " + pa[i]);
finish();
@@ -364,6 +389,68 @@
}
}
+ /**
+ * Override method to add content preview area, specific to the chooser activity.
+ */
+ @Override
+ public void setHeader() {
+ super.setHeader();
+
+ Intent targetIntent = getTargetIntent();
+ if (targetIntent == null) {
+ return;
+ }
+
+ ViewGroup contentPreviewLayout = findViewById(R.id.content_preview);
+ String action = targetIntent.getAction();
+ if (!(Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action))) {
+ contentPreviewLayout.setVisibility(View.GONE);
+ return;
+ }
+
+ showDefaultContentPreview(contentPreviewLayout, targetIntent);
+ }
+
+ private void showDefaultContentPreview(final ViewGroup parentLayout,
+ final Intent targetIntent) {
+ CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
+ TextView previewTextView = findViewById(R.id.content_preview_text);
+ if (sharingText == null) {
+ previewTextView.setVisibility(View.GONE);
+ } else {
+ previewTextView.setText(sharingText);
+ }
+
+ String previewTitle = targetIntent.getStringExtra(Intent.EXTRA_TITLE);
+ TextView previewTitleView = findViewById(R.id.content_preview_title);
+ if (previewTitle == null) {
+ previewTitleView.setVisibility(View.GONE);
+ } else {
+ previewTitleView.setText(previewTitle);
+ }
+
+ ClipData previewData = targetIntent.getClipData();
+ Uri previewThumbnail = null;
+ if (previewData != null) {
+ if (previewData.getItemCount() > 0) {
+ ClipData.Item previewDataItem = previewData.getItemAt(0);
+ previewThumbnail = previewDataItem.getUri();
+ }
+ }
+
+ ImageView previewThumbnailView = findViewById(R.id.content_preview_thumbnail);
+ if (previewThumbnail == null) {
+ previewThumbnailView.setVisibility(View.GONE);
+ } else {
+ Bitmap bmp = loadThumbnail(previewThumbnail, new Size(200, 200));
+ if (bmp == null) {
+ previewThumbnailView.setVisibility(View.GONE);
+ } else {
+ previewThumbnailView.setImageBitmap(bmp);
+ }
+ }
+ }
+
static SharedPreferences getPinnedSharedPrefs(Context context) {
// The code below is because in the android:ui process, no one can hear you scream.
// The package info in the context isn't initialized in the way it is for normal apps,
@@ -630,15 +717,19 @@
}
}
if (targetsToQuery >= QUERY_TARGET_SERVICE_LIMIT) {
- if (DEBUG) Log.d(TAG, "queryTargets hit query target limit "
- + QUERY_TARGET_SERVICE_LIMIT);
+ if (DEBUG) {
+ Log.d(TAG, "queryTargets hit query target limit "
+ + QUERY_TARGET_SERVICE_LIMIT);
+ }
break;
}
}
if (!mServiceConnections.isEmpty()) {
- if (DEBUG) Log.d(TAG, "queryTargets setting watchdog timer for "
- + WATCHDOG_TIMEOUT_MILLIS + "ms");
+ if (DEBUG) {
+ Log.d(TAG, "queryTargets setting watchdog timer for "
+ + WATCHDOG_TIMEOUT_MILLIS + "ms");
+ }
mChooserHandler.sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT,
WATCHDOG_TIMEOUT_MILLIS);
} else {
@@ -969,6 +1060,20 @@
mLaunchedFromUid);
}
+ @VisibleForTesting
+ protected Bitmap loadThumbnail(Uri uri, Size size) {
+ if (uri == null || size == null) {
+ return null;
+ }
+
+ try {
+ return getContentResolver().loadThumbnail(uri, size, null);
+ } catch (IOException | NullPointerException ex) {
+ Log.w(TAG, "Error loading preview thumbnail for uri: " + uri.toString(), ex);
+ }
+ return null;
+ }
+
final class ChooserTargetInfo implements TargetInfo {
private final DisplayResolveInfo mSourceInfo;
private final ResolveInfo mBackupResolveInfo;
@@ -1247,7 +1352,7 @@
UserManager userManager =
(UserManager) getSystemService(Context.USER_SERVICE);
if (ii instanceof LabeledIntent) {
- LabeledIntent li = (LabeledIntent)ii;
+ LabeledIntent li = (LabeledIntent) ii;
ri.resolvePackageName = li.getSourcePackage();
ri.labelRes = li.getLabelResource();
ri.nonLocalizedLabel = li.getNonLocalizedLabel();
@@ -1391,8 +1496,10 @@
}
public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets) {
- if (DEBUG) Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size()
- + " targets");
+ if (DEBUG) {
+ Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size()
+ + " targets");
+ }
if (mTargetsNeedPruning && targets.size() > 0) {
// First proper update since we got an onListRebuilt() with (transient) 0 items.
@@ -1492,8 +1599,9 @@
public int getCount() {
return (int) (
getCallerTargetRowCount()
- + getServiceTargetRowCount()
- + Math.ceil((float) mChooserListAdapter.getStandardTargetCount() / mColumnCount)
+ + getServiceTargetRowCount()
+ + Math.ceil(
+ (float) mChooserListAdapter.getStandardTargetCount() / mColumnCount)
);
}
@@ -1860,7 +1968,7 @@
final int chooserTargetRows = mChooserRowAdapter.getServiceTargetRowCount();
int offset = 0;
- for (int i = 0; i < chooserTargetRows; i++) {
+ for (int i = 0; i < chooserTargetRows; i++) {
final int pos = mChooserRowAdapter.getCallerTargetRowCount() + i;
final int vt = mChooserRowAdapter.getItemViewType(pos);
if (vt != mCachedViewType) {
@@ -1882,4 +1990,65 @@
mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
}
}
+
+
+ /**
+ * Used internally to round image corners while obeying view padding.
+ */
+ public static class RoundedRectImageView extends ImageView {
+ private int mRadius = 0;
+ private Path mPath = new Path();
+
+ public RoundedRectImageView(Context context) {
+ super(context);
+ }
+
+ public RoundedRectImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RoundedRectImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public RoundedRectImageView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ mRadius = context.getResources().getDimensionPixelSize(R.dimen.chooser_corner_radius);
+ }
+
+ private void updatePath(int width, int height) {
+ mPath.reset();
+
+ int imageWidth = width - getPaddingLeft() - getPaddingRight();
+ int imageHeight = height - getPaddingTop() - getPaddingBottom();
+ mPath.addRoundRect(getPaddingLeft(), getPaddingTop(), imageWidth, imageHeight, mRadius,
+ mRadius, Path.Direction.CW);
+ }
+
+ /**
+ * Sets the corner radius on all corners
+ *
+ * param radius 0 for no radius, > 0 for a visible corner radius
+ */
+ public void setRadius(int radius) {
+ mRadius = radius;
+ updatePath(getWidth(), getHeight());
+ }
+
+ @Override
+ protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
+ super.onSizeChanged(width, height, oldWidth, oldHeight);
+ updatePath(width, height);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mRadius != 0) {
+ canvas.clipPath(mPath);
+ }
+
+ super.onDraw(canvas);
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index a50c736..0919911 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1044,7 +1044,10 @@
}
}
- public void setTitleAndIcon() {
+ /**
+ * Configure the area above the app selection list (title, content preview, etc).
+ */
+ public void setHeader() {
if (mAdapter.getCount() == 0 && mAdapter.mPlaceholderCount == 0) {
final TextView titleView = findViewById(R.id.title);
if (titleView != null) {
@@ -1062,23 +1065,6 @@
titleView.setText(title);
}
setTitle(title);
-
- // Try to initialize the title icon if we have a view for it and a title to match
- final ImageView titleIcon = findViewById(R.id.title_icon);
- if (titleIcon != null) {
- ApplicationInfo ai = null;
- try {
- if (!TextUtils.isEmpty(mReferrerPackage)) {
- ai = mPm.getApplicationInfo(mReferrerPackage, 0);
- }
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Could not find referrer package " + mReferrerPackage);
- }
-
- if (ai != null) {
- titleIcon.setImageDrawable(ai.loadIcon(mPm));
- }
- }
}
final ImageView iconView = findViewById(R.id.icon);
@@ -1692,7 +1678,7 @@
mPostListReadyRunnable = new Runnable() {
@Override
public void run() {
- setTitleAndIcon();
+ setHeader();
resetButtonBar();
onListRebuilt();
mPostListReadyRunnable = null;
diff --git a/core/java/com/android/internal/os/AppZygoteInit.java b/core/java/com/android/internal/os/AppZygoteInit.java
index afe6dad..6ba584d 100644
--- a/core/java/com/android/internal/os/AppZygoteInit.java
+++ b/core/java/com/android/internal/os/AppZygoteInit.java
@@ -73,6 +73,9 @@
Log.i(TAG, "Beginning application preload for " + appInfo.packageName);
LoadedApk loadedApk = new LoadedApk(null, appInfo, null, null, false, true, false);
ClassLoader loader = loadedApk.getClassLoader();
+
+ Zygote.allowAppFilesAcrossFork(appInfo);
+
Class<?> cl;
Method m;
try {
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index c8d30b2..9ed7384 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -78,18 +78,7 @@
ClassLoader loader = loadedApk.getClassLoader();
doPreload(loader, WebViewFactory.getWebViewLibrary(appInfo));
- // Add the APK to the Zygote's list of allowed files for children.
- Zygote.nativeAllowFileAcrossFork(appInfo.sourceDir);
- if (appInfo.splitSourceDirs != null) {
- for (String path : appInfo.splitSourceDirs) {
- Zygote.nativeAllowFileAcrossFork(path);
- }
- }
- if (appInfo.sharedLibraryFiles != null) {
- for (String path : appInfo.sharedLibraryFiles) {
- Zygote.nativeAllowFileAcrossFork(path);
- }
- }
+ Zygote.allowAppFilesAcrossFork(appInfo);
Log.i(TAG, "Application preload done");
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index bc7cf87..474d4d7 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -20,6 +20,7 @@
import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
+import android.content.pm.ApplicationInfo;
import android.net.Credentials;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
@@ -370,6 +371,27 @@
protected static native void nativeAllowFileAcrossFork(String path);
/**
+ * Lets children of the zygote inherit open file descriptors that belong to the
+ * ApplicationInfo that is passed in.
+ *
+ * @param appInfo ApplicationInfo of the application
+ */
+ protected static void allowAppFilesAcrossFork(ApplicationInfo appInfo) {
+ Zygote.nativeAllowFileAcrossFork(appInfo.sourceDir);
+ if (appInfo.splitSourceDirs != null) {
+ for (String path : appInfo.splitSourceDirs) {
+ Zygote.nativeAllowFileAcrossFork(path);
+ }
+ }
+ // As well as its shared libs
+ if (appInfo.sharedLibraryFiles != null) {
+ for (String path : appInfo.sharedLibraryFiles) {
+ Zygote.nativeAllowFileAcrossFork(path);
+ }
+ }
+ }
+
+ /**
* Installs a seccomp filter that limits setresuid()/setresgid() to the passed-in range
* @param uidGidMin The smallest allowed uid/gid
* @param uidGidMax The largest allowed uid/gid
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 9afd5d0..51a3b48 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -301,6 +301,7 @@
"libhwui",
"libdl",
"libstatslog",
+ "server_configurable_flags",
],
generated_sources: ["android_util_StatsLog.cpp"],
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c90071a..49598bb 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -31,6 +31,7 @@
#include <binder/Parcel.h>
#include <utils/threads.h>
#include <cutils/properties.h>
+#include <server_configurable_flags/get_flags.h>
#include <SkGraphics.h>
@@ -774,7 +775,17 @@
addOption("-XX:LowMemoryMode");
}
- parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");
+ std::string gc_type_override =
+ server_configurable_flags::GetServerConfigurableFlag("runtime_native", "gctype", "");
+ std::string gc_type_override_temp;
+ if (gc_type_override.empty()) {
+ parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");
+ } else {
+ // Copy the string so it doesn't go out of scope since addOption does not make a copy.
+ gc_type_override_temp = "-Xgc:" + gc_type_override;
+ addOption(gc_type_override_temp.c_str());
+ }
+
parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC=");
/*
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index c0e45b1..67a7441 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -55,6 +55,7 @@
jfieldID ownerUid;
jfieldID inputFeatures;
jfieldID displayId;
+ jfieldID portalToDisplayId;
} gInputWindowHandleClassInfo;
static Mutex gHandleMutex;
@@ -154,6 +155,8 @@
gInputWindowHandleClassInfo.inputFeatures);
mInfo.displayId = env->GetIntField(obj,
gInputWindowHandleClassInfo.displayId);
+ mInfo.portalToDisplayId = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.portalToDisplayId);
jobject inputApplicationHandleObj = env->GetObjectField(obj,
gInputWindowHandleClassInfo.inputApplicationHandle);
@@ -307,6 +310,9 @@
GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz,
"displayId", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.portalToDisplayId, clazz,
+ "portalToDisplayId", "I");
return 0;
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index e0eaf14..712994b 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -999,7 +999,7 @@
optional SettingProto watchdog_poor_network_test_enabled = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto suspend_optimizations_enabled = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto verbose_logging_enabled = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto connected_mac_randomization_enabled = 25 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ reserved 25; // connected_mac_randomization_enabled
optional SettingProto max_dhcp_retry_count = 26 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto mobile_data_transition_wakelock_timeout_ms = 27 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Controls whether WiFi configurations created by a Device Owner app should
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index ded2b35..c42f43a 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -29,8 +29,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alwaysShow="true"
- android:elevation="8dp"
- android:paddingStart="16dp"
android:background="?attr/colorBackgroundFloating" >
<TextView android:id="@+id/profile_button"
android:layout_width="wrap_content"
@@ -46,25 +44,66 @@
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:singleLine="true"/>
- <ImageView android:id="@+id/title_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_marginEnd="16dp"
- android:visibility="gone"
- android:scaleType="fitCenter"
- android:layout_below="@id/profile_button"
- android:layout_alignParentLeft="true"/>
+
<TextView android:id="@+id/title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textAppearance="?attr/textAppearanceMedium"
- android:textSize="14sp"
- android:gravity="start|center_vertical"
+ android:textSize="20sp"
+ android:gravity="center"
android:paddingEnd="?attr/dialogPreferredPadding"
android:paddingTop="12dp"
- android:paddingBottom="12dp"
+ android:paddingBottom="6dp"
android:layout_below="@id/profile_button"
- android:layout_toRightOf="@id/title_icon"/>
+ android:layout_centerHorizontal="true"/>
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/content_preview"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/colorBackgroundFloating">
+
+ <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+ android:id="@+id/content_preview_thumbnail"
+ android:layout_alignParentTop="true"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:gravity="center"
+ android:adjustViewBounds="true"
+ android:maxWidth="90dp"
+ android:maxHeight="90dp"
+ android:scaleType="fitCenter"
+ android:padding="5dp"/>
+
+ <TextView
+ android:id="@+id/content_preview_title"
+ android:layout_alignParentTop="true"
+ android:layout_toEndOf="@id/content_preview_thumbnail"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start|top"
+ android:textAppearance="?attr/textAppearanceMedium"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:paddingStart="15dp"
+ android:paddingEnd="15dp"
+ android:paddingTop="10dp" />
+
+ <TextView
+ android:id="@+id/content_preview_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/content_preview_title"
+ android:layout_toEndOf="@id/content_preview_thumbnail"
+ android:gravity="start|top"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:paddingStart="15dp"
+ android:paddingEnd="15dp"
+ android:paddingTop="10dp"
+ android:paddingBottom="5dp"/>
</RelativeLayout>
<ListView
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index c870683..ef3834c 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -714,4 +714,7 @@
<dimen name="harmful_app_message_padding_bottom">24dp</dimen>
<!-- Line spacing modifier for the message field of the harmful app dialog -->
<item name="harmful_app_message_line_spacing_modifier" type="dimen">1.22</item>
+
+ <!-- chooser corner radius -->
+ <dimen name="chooser_corner_radius">4dp</dimen>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a761baf..6adb4a7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3082,7 +3082,7 @@
<!-- Label for a link to a intent resolver dialog when selecting an editor application -->
<string name="whichEditApplicationLabel">Edit</string>
<!-- Title of intent resolver dialog when selecting a sharing application to run. -->
- <string name="whichSendApplication">Share with</string>
+ <string name="whichSendApplication">Share</string>
<!-- Title of intent resolver dialog when selecting a sharing application to run
and a previously used application is known. -->
<string name="whichSendApplicationNamed">Share with %1$s</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ca8e226..54a3243 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -50,6 +50,10 @@
<java-symbol type="id" name="characterPicker" />
<java-symbol type="id" name="clearDefaultHint" />
<java-symbol type="id" name="contentPanel" />
+ <java-symbol type="id" name="content_preview" />
+ <java-symbol type="id" name="content_preview_thumbnail" />
+ <java-symbol type="id" name="content_preview_text" />
+ <java-symbol type="id" name="content_preview_title" />
<java-symbol type="id" name="current_scene" />
<java-symbol type="id" name="scene_layoutid_cache" />
<java-symbol type="id" name="customPanel" />
@@ -2703,9 +2707,9 @@
<java-symbol type="layout" name="date_picker_month_item_material" />
<java-symbol type="id" name="month_view" />
<java-symbol type="integer" name="config_zen_repeat_callers_threshold" />
+ <java-symbol type="dimen" name="chooser_corner_radius" />
<java-symbol type="layout" name="chooser_grid" />
<java-symbol type="layout" name="resolve_grid_item" />
- <java-symbol type="id" name="title_icon" />
<java-symbol type="id" name="day_picker_view_pager" />
<java-symbol type="layout" name="day_picker_content_material" />
<java-symbol type="drawable" name="scroll_indicator_material" />
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 9d04e63..6a81050 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -37,7 +37,9 @@
mockwebserver \
guava \
androidx.test.runner \
+ androidx.test.ext.junit \
androidx.test.rules \
+ androidx.test.espresso.core \
mockito-target-minus-junit4 \
espresso-core \
ub-uiautomator \
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 86818c6..268bb81 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -62,6 +62,7 @@
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_SMS"/>
+ <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
@@ -1144,6 +1145,14 @@
</intent-filter>
</activity>
+ <activity android:name="android.view.accessibility.AccessibilityTestActivity"
+ android:label="AccessibilityTestActivity" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<!-- Activity-level metadata -->
<meta-data android:name="com.android.frameworks.coretests.isApp" android:value="true" />
<meta-data android:name="com.android.frameworks.coretests.string" android:value="foo" />
diff --git a/core/tests/coretests/res/layout/accessibility_test.xml b/core/tests/coretests/res/layout/accessibility_test.xml
new file mode 100644
index 0000000..1bdd21b
--- /dev/null
+++ b/core/tests/coretests/res/layout/accessibility_test.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button android:id="@+id/appNameBtn"
+ android:text="@string/app_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="60dp"
+ android:bufferType="normal">
+ </Button>
+</LinearLayout>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 0b5bde7..e32b412 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -509,7 +509,6 @@
Settings.Global.WIFI_ALWAYS_REQUESTED,
Settings.Global.WIFI_BADGING_THRESHOLDS,
Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
- Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
Settings.Global.WIFI_COUNTRY_CODE,
Settings.Global.WIFI_DATA_STALL_MIN_TX_BAD,
Settings.Global.WIFI_DATA_STALL_MIN_TX_SUCCESS_WITHOUT_RX,
diff --git a/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java b/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java
new file mode 100644
index 0000000..d0719cb
--- /dev/null
+++ b/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Service;
+import android.app.UiAutomation;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityTestActivity;
+import android.view.accessibility.AccessibilityWindowInfo;
+
+import com.android.compatibility.common.util.TestUtils;
+import com.android.frameworks.coretests.R;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityInteractionControllerTest {
+ static final long TIMEOUT_DEFAULT = 10000; // 10 seconds
+
+ private static Instrumentation sInstrumentation;
+ private static UiAutomation sUiAutomation;
+
+ @Rule
+ public ActivityTestRule<AccessibilityTestActivity> mActivityRule = new ActivityTestRule<>(
+ AccessibilityTestActivity.class, false, false);
+
+ private AccessibilityInteractionController mAccessibilityInteractionController;
+ private ViewRootImpl mViewRootImpl;
+ private View mButton;
+
+ @BeforeClass
+ public static void oneTimeSetup() {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ sUiAutomation = sInstrumentation.getUiAutomation();
+ }
+
+ @AfterClass
+ public static void postTestTearDown() {
+ sUiAutomation.destroy();
+ }
+
+ @Before
+ public void setUp() throws Throwable {
+ launchActivity();
+ enableTouchExploration(true);
+ mActivityRule.runOnUiThread(() -> {
+ mViewRootImpl = mActivityRule.getActivity().getWindow().getDecorView()
+ .getViewRootImpl();
+ mButton = mActivityRule.getActivity().findViewById(R.id.appNameBtn);
+ });
+ mAccessibilityInteractionController =
+ mViewRootImpl.getAccessibilityInteractionController();
+ }
+
+ @After
+ public void tearDown() {
+ enableTouchExploration(false);
+ }
+
+ @Test
+ public void clearAccessibilityFocus_shouldClearFocus() throws Exception {
+ performAccessibilityFocus("com.android.frameworks.coretests:id/appNameBtn");
+ assertTrue("Button should have a11y focus",
+ mButton.isAccessibilityFocused());
+ mAccessibilityInteractionController.clearAccessibilityFocusClientThread();
+ sInstrumentation.waitForIdleSync();
+ assertFalse("Button should not have a11y focus",
+ mButton.isAccessibilityFocused());
+ }
+
+ @Test
+ public void clearAccessibilityFocus_uiThread_shouldClearFocus() throws Exception {
+ performAccessibilityFocus("com.android.frameworks.coretests:id/appNameBtn");
+ assertTrue("Button should have a11y focus",
+ mButton.isAccessibilityFocused());
+ sInstrumentation.runOnMainSync(() -> {
+ mAccessibilityInteractionController.clearAccessibilityFocusClientThread();
+ });
+ assertFalse("Button should not have a11y focus",
+ mButton.isAccessibilityFocused());
+ }
+
+ private void launchActivity() {
+ final Object waitObject = new Object();
+ final int[] location = new int[2];
+ final StringBuilder activityPackage = new StringBuilder();
+ final Rect bounds = new Rect();
+ final StringBuilder activityTitle = new StringBuilder();
+ try {
+ final long executionStartTimeMillis = SystemClock.uptimeMillis();
+ sUiAutomation.setOnAccessibilityEventListener((event) -> {
+ if (event.getEventTime() < executionStartTimeMillis) {
+ return;
+ }
+ synchronized (waitObject) {
+ waitObject.notifyAll();
+ }
+ });
+ enableRetrieveAccessibilityWindows();
+
+ final Activity activity = mActivityRule.launchActivity(null);
+ sInstrumentation.runOnMainSync(() -> {
+ activity.getWindow().getDecorView().getLocationOnScreen(location);
+ activityPackage.append(activity.getPackageName());
+ activityTitle.append(activity.getTitle());
+ });
+ sInstrumentation.waitForIdleSync();
+
+ TestUtils.waitOn(waitObject, () -> {
+ final AccessibilityWindowInfo window = findWindowByTitle(activityTitle);
+ if (window == null) return false;
+ window.getBoundsInScreen(bounds);
+ activity.getWindow().getDecorView().getLocationOnScreen(location);
+ if (bounds.isEmpty()) {
+ return false;
+ }
+ return (!bounds.isEmpty())
+ && (bounds.left == location[0]) && (bounds.top == location[1]);
+ }, TIMEOUT_DEFAULT, "Launch Activity");
+ } finally {
+ sUiAutomation.setOnAccessibilityEventListener(null);
+ }
+ }
+
+ private void enableRetrieveAccessibilityWindows() {
+ AccessibilityServiceInfo info = sUiAutomation.getServiceInfo();
+ info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+ sUiAutomation.setServiceInfo(info);
+ }
+
+ private void enableTouchExploration(boolean enabled) {
+ final Object waitObject = new Object();
+ final AccessibilityManager accessibilityManager =
+ (AccessibilityManager) sInstrumentation.getContext().getSystemService(
+ Service.ACCESSIBILITY_SERVICE);
+ final AccessibilityManager.TouchExplorationStateChangeListener listener = status -> {
+ synchronized (waitObject) {
+ waitObject.notifyAll();
+ }
+ };
+ try {
+ accessibilityManager.addTouchExplorationStateChangeListener(listener);
+ final AccessibilityServiceInfo info = sUiAutomation.getServiceInfo();
+ if (enabled) {
+ info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
+ } else {
+ info.flags &= ~AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
+ }
+ sUiAutomation.setServiceInfo(info);
+ TestUtils.waitOn(waitObject,
+ () -> accessibilityManager.isTouchExplorationEnabled() == enabled,
+ TIMEOUT_DEFAULT,
+ (enabled ? "Enable" : "Disable") + "touch exploration");
+ } finally {
+ accessibilityManager.removeTouchExplorationStateChangeListener(listener);
+ }
+ }
+
+ private void performAccessibilityFocus(String viewId) throws TimeoutException {
+ final AccessibilityNodeInfo node = sUiAutomation.getRootInActiveWindow()
+ .findAccessibilityNodeInfosByViewId(viewId).get(0);
+ // Perform an action and wait for an event
+ sUiAutomation.executeAndWaitForEvent(
+ () -> node.performAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS),
+ event -> event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+ TIMEOUT_DEFAULT);
+ node.refresh();
+ }
+
+ private AccessibilityWindowInfo findWindowByTitle(CharSequence title) {
+ final List<AccessibilityWindowInfo> windows = sUiAutomation.getWindows();
+ AccessibilityWindowInfo returnValue = null;
+ for (int i = 0; i < windows.size(); i++) {
+ final AccessibilityWindowInfo window = windows.get(i);
+ if (TextUtils.equals(title, window.getTitle())) {
+ returnValue = window;
+ } else {
+ window.recycle();
+ }
+ }
+ return returnValue;
+ }
+}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityTestActivity.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityTestActivity.java
new file mode 100644
index 0000000..a17fa73
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityTestActivity.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.accessibility;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
+
+/**
+ * An activity for accessibility test.
+ */
+public class AccessibilityTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ turnOnScreen();
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.accessibility_test);
+ }
+
+ private void turnOnScreen() {
+ setTurnScreenOn(true);
+ setShowWhenLocked(true);
+ KeyguardManager keyguardManager = (KeyguardManager) getSystemService(
+ Context.KEYGUARD_SERVICE);
+ keyguardManager.requestDismissKeyguard(this, null);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index aaa624e..21fcae7 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -16,12 +16,12 @@
package com.android.internal.app;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
@@ -33,12 +33,18 @@
import static org.mockito.Mockito.when;
import android.app.usage.UsageStatsManager;
+import android.content.ClipData;
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.net.Uri;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
@@ -69,7 +75,21 @@
@Test
public void customTitle() throws InterruptedException {
- Intent sendIntent = createSendImageIntent();
+ Intent viewIntent = createViewTextIntent();
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(viewIntent, "chooser test"));
+
+ waitForIdle();
+ onView(withId(R.id.title)).check(matches(withText("chooser test")));
+ }
+
+ @Test
+ public void customTitleIgnoredForSendIntents() throws InterruptedException {
+ Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
@@ -77,12 +97,12 @@
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
mActivityRule.launchActivity(Intent.createChooser(sendIntent, "chooser test"));
waitForIdle();
- onView(withId(R.id.title)).check(matches(withText("chooser test")));
+ onView(withId(R.id.title)).check(matches(withText(R.string.whichSendApplication)));
}
@Test
public void emptyTitle() throws InterruptedException {
- Intent sendIntent = createSendImageIntent();
+ Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
@@ -95,8 +115,72 @@
}
@Test
+ public void emptyPreviewTitleAndThumbnail() throws InterruptedException {
+ Intent sendIntent = createSendTextIntentWithPreview(null, null);
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withId(R.id.content_preview_title)).check(matches(not(isDisplayed())));
+ onView(withId(R.id.content_preview_thumbnail)).check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void visiblePreviewTitleWithoutThumbnail() throws InterruptedException {
+ String previewTitle = "My Content Preview Title";
+ Intent sendIntent = createSendTextIntentWithPreview(previewTitle, null);
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withId(R.id.content_preview_title)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_title)).check(matches(withText(previewTitle)));
+ onView(withId(R.id.content_preview_thumbnail)).check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void visiblePreviewTitleWithInvalidThumbnail() throws InterruptedException {
+ String previewTitle = "My Content Preview Title";
+ Intent sendIntent = createSendTextIntentWithPreview(previewTitle,
+ Uri.parse("tel:(+49)12345789"));
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withId(R.id.content_preview_title)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_thumbnail)).check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void visiblePreviewTitleAndThumbnail() throws InterruptedException {
+ String previewTitle = "My Content Preview Title";
+ Intent sendIntent = createSendTextIntentWithPreview(previewTitle,
+ Uri.parse("android.resource://com.android.frameworks.coretests/"
+ + com.android.frameworks.coretests.R.drawable.test320x240));
+ sOverrides.previewThumbnail = createBitmap();
+ List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+ when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+ Mockito.anyBoolean(),
+ Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+ waitForIdle();
+ onView(withId(R.id.content_preview_title)).check(matches(isDisplayed()));
+ onView(withId(R.id.content_preview_thumbnail)).check(matches(isDisplayed()));
+ }
+
+ @Test
public void twoOptionsAndUserSelectsOne() throws InterruptedException {
- Intent sendIntent = createSendImageIntent();
+ Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
@@ -125,7 +209,7 @@
@Test
public void updateChooserCountsAndModelAfterUserSelection() throws InterruptedException {
- Intent sendIntent = createSendImageIntent();
+ Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
@@ -158,7 +242,7 @@
when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(null);
- Intent sendIntent = createSendImageIntent();
+ Intent sendIntent = createSendTextIntent();
final ChooserWrapperActivity activity = mActivityRule
.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
@@ -186,7 +270,7 @@
Mockito.anyBoolean(),
Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
- Intent sendIntent = createSendImageIntent();
+ Intent sendIntent = createSendTextIntent();
final ChooserWrapperActivity activity = mActivityRule
.launchActivity(Intent.createChooser(sendIntent, null));
waitForIdle();
@@ -197,7 +281,7 @@
@Test
public void hasOtherProfileOneOption() throws Exception {
- Intent sendIntent = createSendImageIntent();
+ Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(2);
ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
@@ -234,7 +318,7 @@
@Test
public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
- Intent sendIntent = createSendImageIntent();
+ Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(3);
ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
@@ -273,7 +357,7 @@
@Test
public void hasLastChosenActivityAndOtherProfile() throws Exception {
- Intent sendIntent = createSendImageIntent();
+ Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos =
createResolvedComponentsForTestWithOtherProfile(3);
ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0);
@@ -308,14 +392,33 @@
assertThat(chosen[0], is(toChoose));
}
- private Intent createSendImageIntent() {
+ private Intent createSendTextIntent() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
- sendIntent.setType("image/jpeg");
return sendIntent;
}
+ private Intent createSendTextIntentWithPreview(String title, Uri imageThumbnail) {
+ Intent sendIntent = new Intent();
+ sendIntent.setAction(Intent.ACTION_SEND);
+ sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
+ sendIntent.putExtra(Intent.EXTRA_TITLE, title);
+ if (imageThumbnail != null) {
+ ClipData.Item clipItem = new ClipData.Item(imageThumbnail);
+ sendIntent.setClipData(new ClipData("Clip Label", new String[]{"image/png"}, clipItem));
+ }
+
+ return sendIntent;
+ }
+
+ private Intent createViewTextIntent() {
+ Intent viewIntent = new Intent();
+ viewIntent.setAction(Intent.ACTION_VIEW);
+ viewIntent.putExtra(Intent.EXTRA_TEXT, "testing intent viewing");
+ return viewIntent;
+ }
+
private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
for (int i = 0; i < numberOfResults; i++) {
@@ -340,4 +443,24 @@
private void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
-}
\ No newline at end of file
+
+ private Bitmap createBitmap() {
+ int width = 200;
+ int height = 200;
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+
+ Paint paint = new Paint();
+ paint.setColor(Color.RED);
+ paint.setStyle(Paint.Style.FILL);
+ canvas.drawPaint(paint);
+
+ paint.setColor(Color.WHITE);
+ paint.setAntiAlias(true);
+ paint.setTextSize(14.f);
+ paint.setTextAlign(Paint.Align.CENTER);
+ canvas.drawText("Hi!", (width / 2.f), (height / 2.f), paint);
+
+ return bitmap;
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 60529f6..637d2ea 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -21,6 +21,9 @@
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.util.Size;
import java.util.function.Function;
@@ -74,6 +77,14 @@
return super.getPackageManager();
}
+ @Override
+ protected Bitmap loadThumbnail(Uri uri, Size size) {
+ if (sOverrides.previewThumbnail != null) {
+ return sOverrides.previewThumbnail;
+ }
+ return super.loadThumbnail(uri, size);
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -85,11 +96,13 @@
public Function<TargetInfo, Boolean> onSafelyStartCallback;
public ResolverListController resolverListController;
public Boolean isVoiceInteraction;
+ public Bitmap previewThumbnail;
public void reset() {
onSafelyStartCallback = null;
isVoiceInteraction = null;
createPackageManager = null;
+ previewThumbnail = null;
resolverListController = mock(ResolverListController.class);
}
}
diff --git a/media/Android.bp b/media/Android.bp
index 3181a29..e7d5faf 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -66,7 +66,9 @@
filegroup {
name: "media1-srcs",
srcs: [
+ "apex/java/android/media/MediaDescription.java",
"apex/java/android/media/MediaParceledListSlice.java",
+ "apex/java/android/media/Rating.java",
"apex/java/android/media/VolumeProvider.java",
"apex/java/android/media/browse/MediaBrowser.java",
"apex/java/android/media/browse/MediaBrowserUtils.java",
diff --git a/media/java/android/media/MediaDescription.aidl b/media/apex/java/android/media/MediaDescription.aidl
similarity index 100%
rename from media/java/android/media/MediaDescription.aidl
rename to media/apex/java/android/media/MediaDescription.aidl
diff --git a/media/java/android/media/MediaDescription.java b/media/apex/java/android/media/MediaDescription.java
similarity index 93%
rename from media/java/android/media/MediaDescription.java
rename to media/apex/java/android/media/MediaDescription.java
index 31079e5..39eeb3e 100644
--- a/media/java/android/media/MediaDescription.java
+++ b/media/apex/java/android/media/MediaDescription.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package android.media;
import android.annotation.Nullable;
@@ -226,7 +242,7 @@
return false;
}
- if (!(o instanceof MediaDescription)){
+ if (!(o instanceof MediaDescription)) {
return false;
}
@@ -375,6 +391,11 @@
return this;
}
+ /**
+ * Build {@link MediaDescription}.
+ *
+ * @return a new media description.
+ */
public MediaDescription build() {
return new MediaDescription(mMediaId, mTitle, mSubtitle, mDescription, mIcon, mIconUri,
mExtras, mMediaUri);
diff --git a/media/java/android/media/Rating.aidl b/media/apex/java/android/media/Rating.aidl
similarity index 100%
rename from media/java/android/media/Rating.aidl
rename to media/apex/java/android/media/Rating.aidl
diff --git a/media/java/android/media/Rating.java b/media/apex/java/android/media/Rating.java
similarity index 93%
rename from media/java/android/media/Rating.java
rename to media/apex/java/android/media/Rating.java
index 04d5364f..ffe7e48 100644
--- a/media/java/android/media/Rating.java
+++ b/media/apex/java/android/media/Rating.java
@@ -33,7 +33,7 @@
* through one of the factory methods.
*/
public final class Rating implements Parcelable {
- private final static String TAG = "Rating";
+ private static final String TAG = "Rating";
/**
* @hide
@@ -55,40 +55,40 @@
* type, but can be used by other classes to indicate they do not support
* Rating.
*/
- public final static int RATING_NONE = 0;
+ public static final int RATING_NONE = 0;
/**
* A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
* indicate the content referred to is a favorite (or not).
*/
- public final static int RATING_HEART = 1;
+ public static final int RATING_HEART = 1;
/**
* A rating style for "thumb up" vs "thumb down".
*/
- public final static int RATING_THUMB_UP_DOWN = 2;
+ public static final int RATING_THUMB_UP_DOWN = 2;
/**
* A rating style with 0 to 3 stars.
*/
- public final static int RATING_3_STARS = 3;
+ public static final int RATING_3_STARS = 3;
/**
* A rating style with 0 to 4 stars.
*/
- public final static int RATING_4_STARS = 4;
+ public static final int RATING_4_STARS = 4;
/**
* A rating style with 0 to 5 stars.
*/
- public final static int RATING_5_STARS = 5;
+ public static final int RATING_5_STARS = 5;
/**
* A rating style expressed as a percentage.
*/
- public final static int RATING_PERCENTAGE = 6;
+ public static final int RATING_PERCENTAGE = 6;
- private final static float RATING_NOT_RATED = -1.0f;
+ private static final float RATING_NOT_RATED = -1.0f;
private final int mRatingStyle;
@@ -116,8 +116,7 @@
dest.writeFloat(mRatingValue);
}
- public static final Parcelable.Creator<Rating> CREATOR
- = new Parcelable.Creator<Rating>() {
+ public static final Parcelable.Creator<Rating> CREATOR = new Parcelable.Creator<Rating>() {
/**
* Rebuilds a Rating previously stored with writeToParcel().
* @param p Parcel object to read the Rating from
@@ -205,7 +204,7 @@
break;
default:
Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
- return null;
+ return null;
}
if ((starRating < 0.0f) || (starRating > maxRating)) {
Log.e(TAG, "Trying to set out of range star-based rating");
@@ -281,16 +280,16 @@
* not star-based, or if it is unrated.
*/
public float getStarRating() {
+ float ratingValue = -1.0f;
switch (mRatingStyle) {
case RATING_3_STARS:
case RATING_4_STARS:
case RATING_5_STARS:
if (isRated()) {
- return mRatingValue;
+ ratingValue = mRatingValue;
}
- default:
- return -1.0f;
}
+ return ratingValue;
}
/**
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index 010a810..7fb51b9 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -22,6 +22,7 @@
coreApp="true">
<uses-permission android:name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<application android:label="@string/app_name"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f523481..ec70f8c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -618,8 +618,6 @@
<string name="wifi_display_certification">Wireless display certification</string>
<!-- Setting Checkbox title whether to enable WiFi Verbose Logging. [CHAR LIMIT=40] -->
<string name="wifi_verbose_logging">Enable Wi\u2011Fi Verbose Logging</string>
- <!-- Setting Checkbox title whether to enable connected MAC randomization -->
- <string name="wifi_connected_mac_randomization">Connected MAC Randomization</string>
<!-- Setting Checkbox title whether to always keep mobile data active. [CHAR LIMIT=80] -->
<string name="mobile_data_always_on">Mobile data always active</string>
<!-- Setting Checkbox title whether to enable hardware acceleration for tethering. [CHAR LIMIT=80] -->
@@ -675,8 +673,6 @@
<string name="wifi_display_certification_summary">Show options for wireless display certification</string>
<!-- Setting Checkbox summary whether to enable Wifi verbose Logging [CHAR LIMIT=80] -->
<string name="wifi_verbose_logging_summary">Increase Wi\u2011Fi logging level, show per SSID RSSI in Wi\u2011Fi Picker</string>
- <!-- Setting Checkbox title whether to enable connected MAC randomization -->
- <string name="wifi_connected_mac_randomization_summary">Randomize MAC address when connecting to Wi\u2011Fi networks</string>
<!-- Label indicating network has been manually marked as metered -->
<string name="wifi_metered_label">Metered</string>
<!-- Label indicating network has been manually marked as unmetered -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 3877c90..6ca8261 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1511,9 +1511,6 @@
Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED,
GlobalSettingsProto.Wifi.VERBOSE_LOGGING_ENABLED);
dumpSetting(s, p,
- Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
- GlobalSettingsProto.Wifi.CONNECTED_MAC_RANDOMIZATION_ENABLED);
- dumpSetting(s, p,
Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
GlobalSettingsProto.Wifi.MAX_DHCP_RETRY_COUNT);
dumpSetting(s, p,
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index f66a57b..9b3d7ed 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -137,8 +137,10 @@
}
public NotificationIconAreaController createNotificationIconAreaController(Context context,
- StatusBar statusBar, StatusBarStateController statusBarStateController) {
- return new NotificationIconAreaController(context, statusBar, statusBarStateController);
+ StatusBar statusBar, StatusBarStateController statusBarStateController,
+ NotificationListener listener) {
+ return new NotificationIconAreaController(context, statusBar, statusBarStateController,
+ listener);
}
public KeyguardIndicationController createKeyguardIndicationController(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
index 968bd28..60dceef 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
@@ -165,6 +165,11 @@
}
}
+ @Override
+ public void clearAccessibilityFocus() {
+ // We should not be here.
+ }
+
public static AccessibilityNodeInfo obtainRootAccessibilityNodeInfo() {
AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
info.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index f3a46ce..0583843 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -20,6 +20,8 @@
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
import static com.android.systemui.statusbar.phone.StatusBar.ENABLE_CHILD_NOTIFICATIONS;
+import android.annotation.SuppressLint;
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.os.RemoteException;
@@ -32,10 +34,13 @@
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
+import java.util.ArrayList;
+
/**
* This class handles listening to notification updates and passing them along to
* NotificationPresenter to be displayed to the user.
*/
+@SuppressLint("OverrideAbstract")
public class NotificationListener extends NotificationListenerWithPlugins {
private static final String TAG = "NotificationListener";
@@ -47,6 +52,7 @@
private final NotificationGroupManager mGroupManager =
Dependency.get(NotificationGroupManager.class);
+ private final ArrayList<NotificationSettingsListener> mSettingsListeners = new ArrayList<>();
private final Context mContext;
protected NotificationPresenter mPresenter;
@@ -55,6 +61,10 @@
mContext = context;
}
+ public void addNotificationSettingsListener(NotificationSettingsListener listener) {
+ mSettingsListeners.add(listener);
+ }
+
@Override
public void onListenerConnected() {
if (DEBUG) Log.d(TAG, "onListenerConnected");
@@ -70,6 +80,8 @@
mEntryManager.addNotification(sbn, currentRanking);
}
});
+ NotificationManager noMan = mContext.getSystemService(NotificationManager.class);
+ onStatusBarIconsBehaviorChanged(noMan.shouldHideSilentStatusBarIcons());
}
@Override
@@ -133,6 +145,13 @@
}
}
+ @Override
+ public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+ for (NotificationSettingsListener listener : mSettingsListeners) {
+ listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
+ }
+ }
+
public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter;
@@ -144,4 +163,10 @@
Log.e(TAG, "Unable to register notification listener", e);
}
}
+
+ public interface NotificationSettingsListener {
+
+ default void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { }
+
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index e86996a..9e99fe9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -11,9 +11,7 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import androidx.annotation.NonNull;
-import androidx.collection.ArrayMap;
-
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.ViewClippingUtil;
@@ -21,6 +19,7 @@
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarStateController;
@@ -28,11 +27,13 @@
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.tuner.TunerService;
import java.util.ArrayList;
import java.util.function.Function;
+import androidx.annotation.NonNull;
+import androidx.collection.ArrayMap;
+
/**
* A controller for the space in the status bar to the left of the system icons. This area is
* normally reserved for notifications.
@@ -46,18 +47,19 @@
private final NotificationEntryManager mEntryManager;
private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
private final StatusBarStateController mStatusBarStateController;
- private final TunerService.Tunable mTunable = new TunerService.Tunable() {
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (key.equals(LOW_PRIORITY)) {
- mShowLowPriority = "1".equals(newValue)
- || !NotificationUtils.useNewInterruptionModel(mContext);
- if (mNotificationScrollLayout != null) {
- updateStatusBarIcons();
+ @VisibleForTesting
+ final NotificationListener.NotificationSettingsListener mSettingsListener =
+ new NotificationListener.NotificationSettingsListener() {
+ @Override
+ public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+ if (NotificationUtils.useNewInterruptionModel(mContext)) {
+ mShowLowPriority = !hideSilentStatusIcons;
+ if (mNotificationScrollLayout != null) {
+ updateStatusBarIcons();
+ }
+ }
}
- }
- }
- };
+ };
private int mIconSize;
private int mIconHPadding;
@@ -71,7 +73,7 @@
private ViewGroup mNotificationScrollLayout;
private Context mContext;
private boolean mFullyDark;
- private boolean mShowLowPriority;
+ private boolean mShowLowPriority = true;
/**
* Ratio representing being awake or in ambient mode, where 1 is dark and 0 awake.
@@ -90,15 +92,15 @@
view -> view instanceof StatusBarWindowView;
public NotificationIconAreaController(Context context, StatusBar statusBar,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ NotificationListener notificationListener) {
mStatusBar = statusBar;
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
mEntryManager = Dependency.get(NotificationEntryManager.class);
mStatusBarStateController = statusBarStateController;
mStatusBarStateController.addCallback(this);
-
- Dependency.get(TunerService.class).addTunable(mTunable, LOW_PRIORITY);
+ notificationListener.addNotificationSettingsListener(mSettingsListener);
initializeNotificationAreaViews(context);
}
@@ -243,6 +245,11 @@
true /* hideRepliedMessages */);
}
+ @VisibleForTesting
+ boolean shouldShouldLowPriorityIcons() {
+ return mShowLowPriority;
+ }
+
/**
* Updates the notification icons for a host layout. This will ensure that the notification
* host layout will have the same icons like the ones in here.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1470d0f..ceadd1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -801,7 +801,8 @@
mNotificationLogger.setUpWithContainer(notifListContainer);
mNotificationIconAreaController = SystemUIFactory.getInstance()
- .createNotificationIconAreaController(context, this, mStatusBarStateController);
+ .createNotificationIconAreaController(
+ context, this, mStatusBarStateController, mNotificationListener);
inflateShelf();
mNotificationIconAreaController.setupShelf(mNotificationShelf);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index c880172..bcf5964 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -17,10 +17,12 @@
package com.android.systemui.statusbar;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
+import android.app.NotificationManager;
import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
@@ -55,6 +57,7 @@
// Dependency mocks:
@Mock private NotificationEntryManager mEntryManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
+ @Mock private NotificationManager mNotificationManager;
private NotificationListener mListener;
private StatusBarNotification mSbn;
@@ -67,6 +70,7 @@
mRemoteInputManager);
mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
new Handler(TestableLooper.get(this).getLooper()));
+ mContext.addMockSystemService(NotificationManager.class, mNotificationManager);
when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
@@ -106,4 +110,28 @@
// RankingMap may be modified by plugins.
verify(mEntryManager).updateNotificationRanking(any());
}
+
+ @Test
+ public void testOnConnectReadStatusBarSetting() {
+ NotificationListener.NotificationSettingsListener settingsListener =
+ mock(NotificationListener.NotificationSettingsListener.class);
+ mListener.addNotificationSettingsListener(settingsListener);
+
+ when(mNotificationManager.shouldHideSilentStatusBarIcons()).thenReturn(true);
+
+ mListener.onListenerConnected();
+
+ verify(settingsListener).onStatusBarIconsBehaviorChanged(true);
+ }
+
+ @Test
+ public void testOnStatusBarIconsBehaviorChanged() {
+ NotificationListener.NotificationSettingsListener settingsListener =
+ mock(NotificationListener.NotificationSettingsListener.class);
+ mListener.addNotificationSettingsListener(settingsListener);
+
+ mListener.onStatusBarIconsBehaviorChanged(true);
+
+ verify(settingsListener).onStatusBarIconsBehaviorChanged(true);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
new file mode 100644
index 0000000..13145b8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.LightBarTransitionsController.DarkIntensityApplier;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationIconAreaControllerTest extends SysuiTestCase {
+
+ @Mock
+ private NotificationListener mListener;
+ @Mock
+ StatusBar mStatusBar;
+ @Mock
+ StatusBarStateController mStatusBarStateController;
+ private NotificationIconAreaController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mController = new NotificationIconAreaController(mContext, mStatusBar,
+ mStatusBarStateController, mListener);
+ }
+
+ @Test
+ public void testNotificationIcons_featureOff() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(), NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
+ assertTrue(mController.shouldShouldLowPriorityIcons());
+ }
+
+ @Test
+ public void testNotificationIcons_featureOn_settingHideIcons() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(), NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
+ mController.mSettingsListener.onStatusBarIconsBehaviorChanged(true);
+
+ assertFalse(mController.shouldShouldLowPriorityIcons());
+ }
+
+ @Test
+ public void testNotificationIcons_featureOn_settingShowIcons() {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(), NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
+ mController.mSettingsListener.onStatusBarIconsBehaviorChanged(false);
+
+ assertTrue(mController.shouldShouldLowPriorityIcons());
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index f88d521..47cd917 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3024,9 +3024,19 @@
}
public void clearAccessibilityFocusNotLocked(int windowId) {
- AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(windowId);
- if (focus != null) {
- focus.performAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ RemoteAccessibilityConnection connection;
+ synchronized (mLock) {
+ connection = getConnectionLocked(windowId);
+ if (connection == null) {
+ return;
+ }
+ }
+ try {
+ connection.getRemote().clearAccessibilityFocus();
+ } catch (RemoteException re) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "Error calling clearAccessibilityFocus()");
+ }
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c8e5d2b..de7c8cc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -79,6 +79,7 @@
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
+import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
@@ -2773,8 +2774,17 @@
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (nri.request.isListen()) continue;
NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
- ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
- (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
+ final int score;
+ final int serial;
+ if (nai != null) {
+ score = nai.getCurrentScore();
+ serial = nai.factorySerialNumber;
+ } else {
+ score = 0;
+ serial = NetworkFactory.SerialNumber.NONE;
+ }
+ ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, serial,
+ nri.request);
}
} else {
loge("Error connecting NetworkFactory");
@@ -2871,7 +2881,7 @@
NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
clearNetworkForRequest(request.requestId);
- sendUpdatedScoreToFactories(request, 0);
+ sendUpdatedScoreToFactories(request, null);
}
}
nai.clearLingerState();
@@ -2947,7 +2957,7 @@
}
rematchAllNetworksAndRequests(null, 0);
if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {
- sendUpdatedScoreToFactories(nri.request, 0);
+ sendUpdatedScoreToFactories(nri.request, null);
}
}
@@ -4532,11 +4542,14 @@
public final String name;
public final Messenger messenger;
public final AsyncChannel asyncChannel;
+ public final int factorySerialNumber;
- public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel) {
+ NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel,
+ int factorySerialNumber) {
this.name = name;
this.messenger = messenger;
this.asyncChannel = asyncChannel;
+ this.factorySerialNumber = factorySerialNumber;
}
}
@@ -4897,10 +4910,12 @@
}
@Override
- public void registerNetworkFactory(Messenger messenger, String name) {
+ public int registerNetworkFactory(Messenger messenger, String name) {
enforceConnectivityInternalPermission();
- NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
+ NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(),
+ NetworkFactory.SerialNumber.nextSerialNumber());
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
+ return nfi.factorySerialNumber;
}
private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
@@ -4992,9 +5007,35 @@
return nri.request.requestId == mDefaultRequest.requestId;
}
+ // TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
+ // changes that would conflict throughout the automerger graph. Having this method temporarily
+ // helps with the process of going through with all these dependent changes across the entire
+ // tree.
public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkMisc networkMisc) {
+ return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities,
+ currentScore, networkMisc, NetworkFactory.SerialNumber.NONE);
+ }
+
+ /**
+ * Register a new agent with ConnectivityService to handle a network.
+ *
+ * @param messenger a messenger for ConnectivityService to contact the agent asynchronously.
+ * @param networkInfo the initial info associated with this network. It can be updated later :
+ * see {@link #updateNetworkInfo}.
+ * @param linkProperties the initial link properties of this network. They can be updated
+ * later : see {@link #updateLinkProperties}.
+ * @param networkCapabilities the initial capabilites of this network. They can be updated
+ * later : see {@link #updateNetworkCapabilities}.
+ * @param currentScore the initial score of the network. See
+ * {@link NetworkAgentInfo#getCurrentScore}.
+ * @param networkMisc metadata about the network. This is never updated.
+ * @param factorySerialNumber the serial number of the factory owning this NetworkAgent.
+ */
+ public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+ LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+ int currentScore, NetworkMisc networkMisc, int factorySerialNumber) {
enforceConnectivityInternalPermission();
LinkProperties lp = new LinkProperties(linkProperties);
@@ -5004,7 +5045,8 @@
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
- mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS);
+ mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS,
+ factorySerialNumber);
// Make sure the network capabilities reflect what the agent info says.
nai.networkCapabilities = mixInCapabilities(nai, nc);
final String extraInfo = networkInfo.getExtraInfo();
@@ -5420,17 +5462,23 @@
NetworkRequest nr = nai.requestAt(i);
// Don't send listening requests to factories. b/17393458
if (nr.isListen()) continue;
- sendUpdatedScoreToFactories(nr, nai.getCurrentScore());
+ sendUpdatedScoreToFactories(nr, nai);
}
}
- private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
+ private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, NetworkAgentInfo nai) {
+ int score = 0;
+ int serial = 0;
+ if (nai != null) {
+ score = nai.getCurrentScore();
+ serial = nai.factorySerialNumber;
+ }
if (VDBG || DDBG){
log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
}
for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
- nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0,
- networkRequest);
+ nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score,
+ serial, networkRequest);
}
}
@@ -5706,7 +5754,7 @@
// TODO - this could get expensive if we have a lot of requests for this
// network. Think about if there is a way to reduce this. Push
// netid->request mapping to each factory?
- sendUpdatedScoreToFactories(nri.request, score);
+ sendUpdatedScoreToFactories(nri.request, newNetwork);
if (isDefaultRequest(nri)) {
isNewDefault = true;
oldDefaultNetwork = currentNetwork;
@@ -5730,7 +5778,7 @@
newNetwork.removeRequest(nri.request.requestId);
if (currentNetwork == newNetwork) {
clearNetworkForRequest(nri.request.requestId);
- sendUpdatedScoreToFactories(nri.request, 0);
+ sendUpdatedScoreToFactories(nri.request, null);
} else {
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
newNetwork.name() +
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 84577f1..4507193 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.VersionedPackage;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
@@ -230,7 +231,6 @@
return null;
}
- // TODO(zezeozue:) Accept current versionCodes of failing packages?
/**
* Called when a process fails either due to a crash or ANR.
*
@@ -239,15 +239,16 @@
*
* <p>This method could be called frequently if there is a severe problem on the device.
*/
- public void onPackageFailure(String[] packages) {
+ public void onPackageFailure(List<VersionedPackage> packages) {
mWorkerHandler.post(() -> {
synchronized (mLock) {
if (mAllObservers.isEmpty()) {
return;
}
- for (int pIndex = 0; pIndex < packages.length; pIndex++) {
- String packageToReport = packages[pIndex];
+ for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
+ String packageToReport = packages.get(pIndex).getPackageName();
+ long packageVersionCode = packages.get(pIndex).getVersionCode();
// Observer that will receive failure for packageToReport
PackageHealthObserver currentObserverToNotify = null;
int currentObserverImpact = Integer.MAX_VALUE;
@@ -258,7 +259,8 @@
PackageHealthObserver registeredObserver = observer.mRegisteredObserver;
if (registeredObserver != null
&& observer.onPackageFailure(packageToReport)) {
- int impact = registeredObserver.onHealthCheckFailed(packageToReport);
+ int impact = registeredObserver.onHealthCheckFailed(packageToReport,
+ packageVersionCode);
if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
&& impact < currentObserverImpact) {
currentObserverToNotify = registeredObserver;
@@ -269,7 +271,7 @@
// Execute action with least user impact
if (currentObserverToNotify != null) {
- currentObserverToNotify.execute(packageToReport);
+ currentObserverToNotify.execute(packageToReport, packageVersionCode);
}
}
}
@@ -313,14 +315,14 @@
* @return any one of {@link PackageHealthObserverImpact} to express the impact
* to the user on {@link #execute}
*/
- @PackageHealthObserverImpact int onHealthCheckFailed(String packageName);
+ @PackageHealthObserverImpact int onHealthCheckFailed(String packageName, long versionCdoe);
/**
* Executes mitigation for {@link #onHealthCheckFailed}.
*
* @return {@code true} if action was executed successfully, {@code false} otherwise
*/
- boolean execute(String packageName);
+ boolean execute(String packageName, long versionCode);
// TODO(zezeozue): Ensure uniqueness?
/**
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index a634b57..f153ab9 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.VersionedPackage;
import android.net.Uri;
import android.os.Binder;
import android.os.Message;
@@ -60,6 +61,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collections;
+import java.util.List;
/**
* Controls error conditions in applications.
@@ -411,7 +413,7 @@
} else {
// If a non-persistent app is stuck in crash loop, we want to inform
// the package watchdog, maybe an update or experiment can be rolled back.
- mPackageWatchdog.onPackageFailure(r.getPackageList());
+ mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode());
}
}
@@ -830,7 +832,7 @@
void handleShowAnrUi(Message msg) {
Dialog dialogToShow = null;
- String[] packageList = null;
+ List<VersionedPackage> packageList = null;
synchronized (mService) {
AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj;
final ProcessRecord proc = data.proc;
@@ -839,7 +841,7 @@
return;
}
if (!proc.isPersistent()) {
- packageList = proc.getPackageList();
+ packageList = proc.getPackageListWithVersionCode();
}
if (proc.anrDialog != null) {
Slog.e(TAG, "App already has anr dialog: " + proc);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 580d688..7ae77d5 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -32,6 +32,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.VersionedPackage;
import android.content.res.CompatibilityInfo;
import android.os.Binder;
import android.os.Debug;
@@ -66,6 +67,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* Full information about a particular process that
@@ -974,6 +976,18 @@
return list;
}
+ public List<VersionedPackage> getPackageListWithVersionCode() {
+ int size = pkgList.size();
+ if (size == 0) {
+ return null;
+ }
+ List<VersionedPackage> list = new ArrayList<>();
+ for (int i = 0; i < pkgList.size(); i++) {
+ list.add(new VersionedPackage(pkgList.keyAt(i), pkgList.valueAt(i).appVersion));
+ }
+ return list;
+ }
+
WindowProcessController getWindowProcessController() {
return mWindowProcessController;
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index d0cff25..cd4ce2d 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -235,6 +235,8 @@
public final Messenger messenger;
public final AsyncChannel asyncChannel;
+ public final int factorySerialNumber;
+
// Used by ConnectivityService to keep track of 464xlat.
public Nat464Xlat clatd;
@@ -252,7 +254,7 @@
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
NetworkMisc misc, ConnectivityService connService, INetd netd,
- INetworkManagementService nms) {
+ INetworkManagementService nms, int factorySerialNumber) {
this.messenger = messenger;
asyncChannel = ac;
network = net;
@@ -266,6 +268,7 @@
mContext = context;
mHandler = handler;
networkMisc = misc;
+ this.factorySerialNumber = factorySerialNumber;
}
/**
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2508844..7e95f10 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -54,6 +54,7 @@
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
+import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
@@ -942,7 +943,8 @@
try {
mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
mNetworkInfo, mNetworkCapabilities, lp,
- ConnectivityConstants.VPN_DEFAULT_SCORE, networkMisc) {
+ ConnectivityConstants.VPN_DEFAULT_SCORE, networkMisc,
+ NetworkFactory.SerialNumber.VPN) {
@Override
public void unwanted() {
// We are user controlled, not driven by NetworkRequest.
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 467b192..e68bcda 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2366,6 +2366,28 @@
}
@Override
+ public boolean shouldHideSilentStatusIcons(String callingPkg) {
+ checkCallerIsSameApp(callingPkg);
+
+ if (isCallerSystemOrPhone()
+ || mListeners.isListenerPackage(callingPkg)) {
+ return mPreferencesHelper.shouldHideSilentStatusIcons();
+ } else {
+ throw new SecurityException("Only available for notification listeners");
+ }
+ }
+
+ @Override
+ public void setHideSilentStatusIcons(boolean hide) {
+ checkCallerIsSystem();
+
+ mPreferencesHelper.setHideSilentStatusIcons(hide);
+ handleSavePolicyFile();
+
+ mListeners.onStatusBarIconsBehaviorChanged(hide);
+ }
+
+ @Override
public int getPackageImportance(String pkg) {
checkCallerIsSystemOrSameApp(pkg);
return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
@@ -7324,6 +7346,20 @@
return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
}
+ public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+ for (final ManagedServiceInfo info : getServices()) {
+ mHandler.post(() -> {
+ final INotificationListener listener = (INotificationListener) info.service;
+ try {
+ listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "unable to notify listener "
+ + "(hideSilentStatusIcons): " + listener, ex);
+ }
+ });
+ }
+ }
+
/**
* asynchronously notify all listeners about a new notification
*
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 3f0043c..6ed4f5c 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -76,6 +76,7 @@
private static final String TAG_CHANNEL = "channel";
private static final String TAG_GROUP = "channelGroup";
private static final String TAG_DELEGATE = "delegate";
+ private static final String TAG_STATUS_ICONS = "status_icons";
private static final String ATT_VERSION = "version";
private static final String ATT_NAME = "name";
@@ -89,10 +90,13 @@
private static final String ATT_APP_USER_LOCKED_FIELDS = "app_user_locked_fields";
private static final String ATT_ENABLED = "enabled";
private static final String ATT_USER_ALLOWED = "allowed";
+ private static final String ATT_HIDE_SILENT = "hide_silent";
private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED;
+ @VisibleForTesting
+ static final boolean DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS = false;
private static final boolean DEFAULT_SHOW_BADGE = true;
private static final boolean DEFAULT_ALLOW_BUBBLE = true;
private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE = false;
@@ -124,6 +128,7 @@
private SparseBooleanArray mBadgingEnabled;
private boolean mAreChannelsBypassingDnd;
+ private boolean mHideSilentStatusBarIcons;
public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
ZenModeHelper zenHelper) {
@@ -143,9 +148,8 @@
String tag = parser.getName();
if (!TAG_RANKING.equals(tag)) return;
synchronized (mPackagePreferences) {
- // Clobber groups and channels with the xml, but don't delete other data that wasn't present
-
- // at the time of serialization.
+ // Clobber groups and channels with the xml, but don't delete other data that wasn't
+ // present at the time of serialization.
mRestoredWithoutUids.clear();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
@@ -153,7 +157,10 @@
return;
}
if (type == XmlPullParser.START_TAG) {
- if (TAG_PACKAGE.equals(tag)) {
+ if (TAG_STATUS_ICONS.equals(tag)) {
+ mHideSilentStatusBarIcons = XmlUtils.readBooleanAttribute(
+ parser, ATT_HIDE_SILENT, DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
+ } else if (TAG_PACKAGE.equals(tag)) {
int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
String name = parser.getAttributeValue(null, ATT_NAME);
if (!TextUtils.isEmpty(name)) {
@@ -375,6 +382,11 @@
public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
out.startTag(null, TAG_RANKING);
out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
+ if (mHideSilentStatusBarIcons != DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS) {
+ out.startTag(null, TAG_STATUS_ICONS);
+ out.attribute(null, ATT_HIDE_SILENT, String.valueOf(mHideSilentStatusBarIcons));
+ out.endTag(null, TAG_STATUS_ICONS);
+ }
synchronized (mPackagePreferences) {
final int N = mPackagePreferences.size();
@@ -781,6 +793,14 @@
}
}
+ public boolean shouldHideSilentStatusIcons() {
+ return mHideSilentStatusBarIcons;
+ }
+
+ public void setHideSilentStatusIcons(boolean hide) {
+ mHideSilentStatusBarIcons = hide;
+ }
+
public void lockChannelsForOEM(String[] appOrChannelList) {
if (appOrChannelList == null) {
return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 6f1eeeb..dc18dfc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -61,6 +61,10 @@
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import android.content.rollback.IRollbackManager;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -263,6 +267,8 @@
return getStagedSessions();
case "uninstall-system-updates":
return uninstallSystemUpdates();
+ case "rollback-app":
+ return runRollbackApp();
default: {
String nextArg = getNextArg();
if (nextArg == null) {
@@ -348,6 +354,55 @@
return 1;
}
+ private int runRollbackApp() {
+ final PrintWriter pw = getOutPrintWriter();
+
+ final String packageName = getNextArgRequired();
+ if (packageName == null) {
+ pw.println("Error: package name not specified");
+ return 1;
+ }
+
+ final LocalIntentReceiver receiver = new LocalIntentReceiver();
+ try {
+ IRollbackManager rm = IRollbackManager.Stub.asInterface(
+ ServiceManager.getService(Context.ROLLBACK_SERVICE));
+
+ RollbackInfo rollback = null;
+ for (RollbackInfo r : (List<RollbackInfo>) rm.getAvailableRollbacks().getList()) {
+ for (PackageRollbackInfo info : r.getPackages()) {
+ if (packageName.equals(info.getPackageName())) {
+ rollback = r;
+ break;
+ }
+ }
+ }
+
+ if (rollback == null) {
+ pw.println("No available rollbacks for: " + packageName);
+ return 1;
+ }
+
+ rm.commitRollback(rollback.getRollbackId(),
+ ParceledListSlice.<VersionedPackage>emptyList(),
+ "com.android.shell", receiver.getIntentSender());
+ } catch (RemoteException re) {
+ // Cannot happen.
+ }
+
+ final Intent result = receiver.getResult();
+ final int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
+ RollbackManager.STATUS_FAILURE);
+ if (status == RollbackManager.STATUS_SUCCESS) {
+ pw.println("Success");
+ return 0;
+ } else {
+ pw.println("Failure ["
+ + result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE) + "]");
+ return 1;
+ }
+ }
+
private void setParamsSize(InstallParams params, String inPath) {
if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
final ParcelFileDescriptor fd = openFileForSystem(inPath, "r");
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
new file mode 100644
index 0000000..8dd0760
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.rollback;
+
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.PackageRollbackInfo.RestoreInfo;
+import android.content.rollback.RollbackInfo;
+import android.os.storage.StorageManager;
+import android.util.IntArray;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.Installer;
+import com.android.server.pm.Installer.InstallerException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Encapsulates the logic for initiating userdata snapshots and rollbacks via installd.
+ */
+@VisibleForTesting
+// TODO(narayan): Reason about the failure scenarios that involve one or more IPCs to installd
+// failing. We need to decide what course of action to take if calls to snapshotAppData or
+// restoreAppDataSnapshot fail.
+public class AppDataRollbackHelper {
+ private static final String TAG = "RollbackManager";
+
+ private final Installer mInstaller;
+
+ public AppDataRollbackHelper(Installer installer) {
+ mInstaller = installer;
+ }
+
+ /**
+ * Creates an app data snapshot for a specified {@code packageName} for {@code installedUsers},
+ * a specified set of users for whom the package is installed.
+ *
+ * @return a list of users for which the snapshot is pending, usually because data for one or
+ * more users is still credential locked.
+ */
+ public IntArray snapshotAppData(String packageName, int[] installedUsers) {
+ final IntArray pendingBackups = new IntArray();
+ for (int user : installedUsers) {
+ final int storageFlags;
+ if (isUserCredentialLocked(user)) {
+ // We've encountered a user that hasn't unlocked on a FBE device, so we can't copy
+ // across app user data until the user unlocks their device.
+ Log.v(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup.");
+ storageFlags = Installer.FLAG_STORAGE_DE;
+ pendingBackups.add(user);
+ } else {
+ storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE;
+ }
+
+ try {
+ mInstaller.snapshotAppData(packageName, user, storageFlags);
+ } catch (InstallerException ie) {
+ Log.e(TAG, "Unable to create app data snapshot for: " + packageName
+ + ", userId: " + user, ie);
+ }
+ }
+
+ return pendingBackups;
+ }
+
+ /**
+ * Restores an app data snapshot for a specified package ({@code packageName},
+ * {@code rollbackData}) for a specified {@code userId}.
+ *
+ * @return {@code true} iff. a change to the {@code rollbackData} has been made. Changes to
+ * {@code rollbackData} are restricted to the removal or addition of {@code userId} to
+ * the list of pending backups or restores.
+ */
+ public boolean restoreAppData(String packageName, RollbackData rollbackData,
+ int userId, int appId, long ceDataInode, String seInfo) {
+ if (rollbackData == null) {
+ return false;
+ }
+
+ if (!rollbackData.inProgress) {
+ Log.e(TAG, "Request to restore userData for: " + packageName
+ + ", but no rollback in progress.");
+ return false;
+ }
+
+ PackageRollbackInfo packageInfo = RollbackManagerServiceImpl.getPackageRollbackInfo(
+ rollbackData, packageName);
+ int storageFlags = Installer.FLAG_STORAGE_DE;
+
+ final IntArray pendingBackups = packageInfo.getPendingBackups();
+ final List<RestoreInfo> pendingRestores = packageInfo.getPendingRestores();
+ boolean changedRollbackData = false;
+
+ // If we still have a userdata backup pending for this user, it implies that the user
+ // hasn't unlocked their device between the point of backup and the point of restore,
+ // so the data cannot have changed. We simply skip restoring CE data in this case.
+ if (pendingBackups != null && pendingBackups.indexOf(userId) != -1) {
+ pendingBackups.remove(pendingBackups.indexOf(userId));
+ changedRollbackData = true;
+ } else {
+ // There's no pending CE backup for this user, which means that we successfully
+ // managed to backup data for the user, which means we seek to restore it
+ if (isUserCredentialLocked(userId)) {
+ // We've encountered a user that hasn't unlocked on a FBE device, so we can't
+ // copy across app user data until the user unlocks their device.
+ pendingRestores.add(new RestoreInfo(userId, appId, seInfo));
+ changedRollbackData = true;
+ } else {
+ // This user has unlocked, we can proceed to restore both CE and DE data.
+ storageFlags = storageFlags | Installer.FLAG_STORAGE_CE;
+ }
+ }
+
+ try {
+ mInstaller.restoreAppDataSnapshot(packageName, appId, ceDataInode,
+ seInfo, userId, storageFlags);
+ } catch (InstallerException ie) {
+ Log.e(TAG, "Unable to restore app data snapshot: " + packageName, ie);
+ }
+
+ return changedRollbackData;
+ }
+
+ /**
+ * Computes the list of pending backups and restores for {@code userId} given lists of
+ * available and recent rollbacks. Packages pending backup for the given user are added
+ * to {@code pendingBackups} and packages pending restore are added to {@code pendingRestores}
+ * along with their corresponding {@code RestoreInfo}.
+ *
+ * @return the list of {@code RollbackData} that have been modified during this computation.
+ */
+ public List<RollbackData> computePendingBackupsAndRestores(int userId,
+ ArrayList<String> pendingBackupPackages, Map<String, RestoreInfo> pendingRestores,
+ List<RollbackData> availableRollbacks, List<RollbackInfo> recentRollbacks) {
+ List<RollbackData> rd = new ArrayList<>();
+ // First check with the list of available rollbacks to see whether there are any
+ // pending backup operations that we've not managed to execute.
+ for (RollbackData data : availableRollbacks) {
+ for (PackageRollbackInfo info : data.packages) {
+ final IntArray pendingBackupUsers = info.getPendingBackups();
+ if (pendingBackupUsers != null) {
+ final int idx = pendingBackupUsers.indexOf(userId);
+ if (idx != -1) {
+ pendingBackupPackages.add(info.getPackageName());
+ pendingBackupUsers.remove(idx);
+ if (rd.indexOf(data) == -1) {
+ rd.add(data);
+ }
+ }
+ }
+ }
+ }
+
+ // Then check with the list of recently executed rollbacks to see whether there are
+ // any rollback operations
+ for (RollbackInfo data : recentRollbacks) {
+ for (PackageRollbackInfo info : data.getPackages()) {
+ final RestoreInfo ri = info.getRestoreInfo(userId);
+ if (ri != null) {
+ if (pendingBackupPackages.contains(info.getPackageName())) {
+ // This implies that the user hasn't unlocked their device between
+ // the request to backup data for this user and the request to restore
+ // it, so we do nothing here.
+ pendingBackupPackages.remove(info.getPackageName());
+ } else {
+ pendingRestores.put(info.getPackageName(), ri);
+ }
+
+ info.removeRestoreInfo(ri);
+ }
+ }
+ }
+
+ return rd;
+ }
+
+ /**
+ * Commits the list of pending backups and restores for a given {@code userId}.
+ */
+ public void commitPendingBackupAndRestoreForUser(int userId,
+ ArrayList<String> pendingBackups, Map<String, RestoreInfo> pendingRestores) {
+ if (!pendingBackups.isEmpty()) {
+ for (String packageName : pendingBackups) {
+ try {
+ mInstaller.snapshotAppData(packageName, userId, Installer.FLAG_STORAGE_CE);
+ } catch (InstallerException ie) {
+ Log.e(TAG, "Unable to create app data snapshot for: " + packageName, ie);
+ }
+ }
+ }
+
+ // TODO(narayan): Should we perform the restore before the backup for packages that have
+ // both backups and restores pending ? We could get into this case if we have a pending
+ // restore from a rollback + a snapshot request from a new restore.
+ if (!pendingRestores.isEmpty()) {
+ for (String packageName : pendingRestores.keySet()) {
+ try {
+ final RestoreInfo ri = pendingRestores.get(packageName);
+
+ // TODO(narayan): Verify that the user of "0" for ceDataInode is accurate
+ // here. We know that the user has unlocked (and that their CE data is
+ // available) so we shouldn't need to resort to the fallback path.
+ mInstaller.restoreAppDataSnapshot(packageName, ri.appId,
+ 0 /* ceDataInode */, ri.seInfo, userId, Installer.FLAG_STORAGE_CE);
+ } catch (InstallerException ie) {
+ Log.e(TAG, "Unable to restore app data snapshot for: " + packageName, ie);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return {@code true} iff. {@code userId} is locked on an FBE device.
+ */
+ @VisibleForTesting
+ public boolean isUserCredentialLocked(int userId) {
+ return StorageManager.isFileEncryptedNativeOrEmulated()
+ && !StorageManager.isUserKeyUnlocked(userId);
+ }
+}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerService.java b/services/core/java/com/android/server/rollback/RollbackManagerService.java
index 4b5e764..ba6cddd 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerService.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerService.java
@@ -39,4 +39,9 @@
mService = new RollbackManagerServiceImpl(getContext());
publishBinderService(Context.ROLLBACK_SERVICE, mService);
}
+
+ @Override
+ public void onUnlockUser(int user) {
+ mService.onUnlockUser(user);
+ }
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 289618e..5eb137b 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -31,6 +31,7 @@
import android.content.pm.VersionedPackage;
import android.content.rollback.IRollbackManager;
import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Binder;
@@ -39,14 +40,13 @@
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.storage.StorageManager;
+import android.util.IntArray;
import android.util.Log;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
import com.android.server.pm.Installer;
-import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.PackageManagerServiceUtils;
import java.io.File;
@@ -111,6 +111,7 @@
private final HandlerThread mHandlerThread;
private final Installer mInstaller;
private final RollbackPackageHealthObserver mPackageHealthObserver;
+ private final AppDataRollbackHelper mUserdataHelper;
RollbackManagerServiceImpl(Context context) {
mContext = context;
@@ -124,6 +125,7 @@
mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
+ mUserdataHelper = new AppDataRollbackHelper(mInstaller);
// Kick off loading of the rollback data from strorage in a background
// thread.
@@ -424,6 +426,35 @@
}
}
+ void onUnlockUser(int userId) {
+ getHandler().post(() -> {
+ final ArrayList<String> pendingBackupPackages = new ArrayList<>();
+ final Map<String, RestoreInfo> pendingRestorePackages = new HashMap<>();
+ final List<RollbackData> changed;
+ synchronized (mLock) {
+ ensureRollbackDataLoadedLocked();
+ changed = mUserdataHelper.computePendingBackupsAndRestores(userId,
+ pendingBackupPackages, pendingRestorePackages, mAvailableRollbacks,
+ mRecentlyExecutedRollbacks);
+ }
+
+ mUserdataHelper.commitPendingBackupAndRestoreForUser(userId,
+ pendingBackupPackages, pendingRestorePackages);
+
+ for (RollbackData rd : changed) {
+ try {
+ mRollbackStore.saveAvailableRollback(rd);
+ } catch (IOException ioe) {
+ Log.e(TAG, "Unable to save rollback info for : " + rd.rollbackId, ioe);
+ }
+ }
+
+ synchronized (mLock) {
+ mRollbackStore.saveRecentlyExecutedRollbacks(mRecentlyExecutedRollbacks);
+ }
+ });
+ }
+
/**
* Load rollback data from storage if it has not already been loaded.
* After calling this funciton, mAvailableRollbacks and
@@ -533,6 +564,20 @@
// that are necessary to keep track of.
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
+
+ // This should never happen because we can't have any pending backups left after
+ // a rollback has been executed. See AppDataRollbackHelper#restoreAppData where we
+ // clear all pending backups at the point of restore because they're guaranteed to be
+ // no-ops.
+ //
+ // We may, however, have one or more pending restores left to handle.
+ for (PackageRollbackInfo target : rollback.getPackages()) {
+ if (target.getPendingBackups().size() > 0) {
+ Log.e(TAG, "No backups allowed to be pending for: " + target);
+ target.getPendingBackups().clear();
+ }
+ }
+
mRecentlyExecutedRollbacks.add(rollback);
mRollbackStore.saveRecentlyExecutedRollbacks(mRecentlyExecutedRollbacks);
}
@@ -701,27 +746,12 @@
VersionedPackage installedVersion = new VersionedPackage(packageName,
installedPackage.getLongVersionCode());
- for (int user : installedUsers) {
- final int storageFlags;
- if (StorageManager.isFileEncryptedNativeOrEmulated()
- && !StorageManager.isUserKeyUnlocked(user)) {
- // We've encountered a user that hasn't unlocked on a FBE device, so we can't copy
- // across app user data until the user unlocks their device.
- Log.e(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup.");
- storageFlags = Installer.FLAG_STORAGE_DE;
- } else {
- storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE;
- }
- try {
- mInstaller.snapshotAppData(packageName, user, storageFlags);
- } catch (InstallerException ie) {
- Log.e(TAG, "Unable to create app data snapshot for: " + packageName, ie);
- }
- }
+ final IntArray pendingBackups = mUserdataHelper.snapshotAppData(packageName,
+ installedUsers);
- PackageRollbackInfo info = new PackageRollbackInfo(newVersion, installedVersion);
-
+ PackageRollbackInfo info = new PackageRollbackInfo(newVersion, installedVersion,
+ pendingBackups, new ArrayList<>());
RollbackData data;
try {
synchronized (mLock) {
@@ -760,40 +790,24 @@
}
getHandler().post(() -> {
- PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
final RollbackData rollbackData = getRollbackForPackage(packageName);
- if (rollbackData == null) {
- pmi.finishPackageInstall(token, false);
- return;
- }
-
- if (!rollbackData.inProgress) {
- Log.e(TAG, "Request to restore userData for: " + packageName
- + ", but no rollback in progress.");
- pmi.finishPackageInstall(token, false);
- return;
- }
-
- final int storageFlags;
- if (StorageManager.isFileEncryptedNativeOrEmulated()
- && !StorageManager.isUserKeyUnlocked(userId)) {
- // We've encountered a user that hasn't unlocked on a FBE device, so we can't copy
- // across app user data until the user unlocks their device.
- Log.e(TAG, "User: " + userId + " isn't unlocked, skipping CE userdata restore.");
-
- storageFlags = Installer.FLAG_STORAGE_DE;
- } else {
- storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE;
- }
-
- try {
- mInstaller.restoreAppDataSnapshot(packageName, appId, ceDataInode,
- seInfo, userId, storageFlags);
- } catch (InstallerException ie) {
- Log.e(TAG, "Unable to restore app data snapshot: " + packageName, ie);
- }
-
+ final boolean changedRollbackData = mUserdataHelper.restoreAppData(packageName,
+ rollbackData, userId, appId, ceDataInode, seInfo);
+ final PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
pmi.finishPackageInstall(token, false);
+
+ // We've updated metadata about this rollback, so save it to flash.
+ if (changedRollbackData) {
+ try {
+ mRollbackStore.saveAvailableRollback(rollbackData);
+ } catch (IOException ioe) {
+ // TODO(narayan): What is the right thing to do here ? This isn't a fatal error,
+ // since it will only result in us trying to restore data again, which will be
+ // a no-op if there's no data available.
+ Log.e(TAG, "Unable to save available rollback: " + packageName, ioe);
+ }
+ }
});
}
@@ -900,10 +914,8 @@
ensureRollbackDataLoadedLocked();
for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
RollbackData data = mAvailableRollbacks.get(i);
- for (PackageRollbackInfo info : data.packages) {
- if (info.getPackageName().equals(packageName)) {
- return data;
- }
+ if (getPackageRollbackInfo(data, packageName) != null) {
+ return data;
}
}
}
@@ -926,6 +938,22 @@
}
}
}
+
+ return null;
+ }
+
+ /**
+ * Returns the {@code PackageRollbackInfo} associated with {@code packageName} from
+ * a specified {@code RollbackData}.
+ */
+ static PackageRollbackInfo getPackageRollbackInfo(RollbackData data,
+ String packageName) {
+ for (PackageRollbackInfo info : data.packages) {
+ if (info.getPackageName().equals(packageName)) {
+ return info;
+ }
+ }
+
return null;
}
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 2880103..f50e776 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -54,8 +54,8 @@
}
@Override
- public int onHealthCheckFailed(String packageName) {
- RollbackInfo rollback = getAvailableRollback(packageName);
+ public int onHealthCheckFailed(String packageName, long versionCode) {
+ RollbackInfo rollback = getAvailableRollback(packageName, versionCode);
if (rollback == null) {
// Don't handle the notification, no rollbacks available for the package
return PackageHealthObserverImpact.USER_IMPACT_NONE;
@@ -65,8 +65,8 @@
}
@Override
- public boolean execute(String packageName) {
- RollbackInfo rollback = getAvailableRollback(packageName);
+ public boolean execute(String packageName, long versionCode) {
+ RollbackInfo rollback = getAvailableRollback(packageName, versionCode);
if (rollback == null) {
// Expected a rollback to be available, what happened?
return false;
@@ -110,11 +110,12 @@
PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
}
- private RollbackInfo getAvailableRollback(String packageName) {
+ private RollbackInfo getAvailableRollback(String packageName, long versionCode) {
for (RollbackInfo rollback : mRollbackManager.getAvailableRollbacks()) {
for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
- if (packageName.equals(packageRollback.getPackageName())) {
- // TODO(zezeozue): Only rollback if rollback version == failed package version
+ if (packageName.equals(packageRollback.getPackageName())
+ && packageRollback.getVersionRolledBackFrom().getVersionCode()
+ == versionCode) {
return rollback;
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 98ebb09..c70f47d 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -16,9 +16,12 @@
package com.android.server.rollback;
+import android.annotation.NonNull;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.content.rollback.RollbackInfo;
+import android.util.IntArray;
import android.util.Log;
import libcore.io.IoUtils;
@@ -99,6 +102,64 @@
}
/**
+ * Converts an {@code JSONArray} of integers to an {@code IntArray}.
+ */
+ private static @NonNull IntArray convertToIntArray(@NonNull JSONArray jsonArray)
+ throws JSONException {
+ if (jsonArray.length() == 0) {
+ return new IntArray();
+ }
+
+ final int[] ret = new int[jsonArray.length()];
+ for (int i = 0; i < ret.length; ++i) {
+ ret[i] = jsonArray.getInt(i);
+ }
+
+ return IntArray.wrap(ret);
+ }
+
+ /**
+ * Converts an {@code IntArray} into an {@code JSONArray} of integers.
+ */
+ private static @NonNull JSONArray convertToJsonArray(@NonNull IntArray intArray) {
+ JSONArray jsonArray = new JSONArray();
+ for (int i = 0; i < intArray.size(); ++i) {
+ jsonArray.put(intArray.get(i));
+ }
+
+ return jsonArray;
+ }
+
+ private static @NonNull JSONArray convertToJsonArray(@NonNull List<RestoreInfo> list)
+ throws JSONException {
+ JSONArray jsonArray = new JSONArray();
+ for (RestoreInfo ri : list) {
+ JSONObject jo = new JSONObject();
+ jo.put("userId", ri.userId);
+ jo.put("appId", ri.appId);
+ jo.put("seInfo", ri.seInfo);
+ jsonArray.put(jo);
+ }
+
+ return jsonArray;
+ }
+
+ private static @NonNull ArrayList<RestoreInfo> convertToRestoreInfoArray(
+ @NonNull JSONArray array) throws JSONException {
+ ArrayList<RestoreInfo> restoreInfos = new ArrayList<>();
+
+ for (int i = 0; i < array.length(); ++i) {
+ JSONObject jo = array.getJSONObject(i);
+ restoreInfos.add(new RestoreInfo(
+ jo.getInt("userId"),
+ jo.getInt("appId"),
+ jo.getString("seInfo")));
+ }
+
+ return restoreInfos;
+ }
+
+ /**
* Reads the list of recently executed rollbacks from persistent storage.
*/
List<RollbackInfo> loadRecentlyExecutedRollbacks() {
@@ -239,6 +300,12 @@
JSONObject json = new JSONObject();
json.put("versionRolledBackFrom", toJson(info.getVersionRolledBackFrom()));
json.put("versionRolledBackTo", toJson(info.getVersionRolledBackTo()));
+
+ IntArray pendingBackups = info.getPendingBackups();
+ List<RestoreInfo> pendingRestores = info.getPendingRestores();
+ json.put("pendingBackups", convertToJsonArray(pendingBackups));
+ json.put("pendingRestores", convertToJsonArray(pendingRestores));
+
return json;
}
@@ -247,7 +314,14 @@
json.getJSONObject("versionRolledBackFrom"));
VersionedPackage versionRolledBackTo = versionedPackageFromJson(
json.getJSONObject("versionRolledBackTo"));
- return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo);
+
+ final IntArray pendingBackups = convertToIntArray(
+ json.getJSONArray("pendingBackups"));
+ final ArrayList<RestoreInfo> pendingRestores = convertToRestoreInfoArray(
+ json.getJSONArray("pendingRestores"));
+
+ return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
+ pendingBackups, pendingRestores);
}
private JSONArray versionedPackagesToJson(List<VersionedPackage> packages)
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a83ffe8..080f965 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -29,6 +29,7 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.InsetsState.TYPE_IME;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
@@ -43,6 +44,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
@@ -140,9 +142,11 @@
import android.graphics.Region;
import android.graphics.Region.Op;
import android.hardware.display.DisplayManagerInternal;
+import android.os.Binder;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -157,6 +161,7 @@
import android.view.Gravity;
import android.view.InputChannel;
import android.view.InputDevice;
+import android.view.InputWindowHandle;
import android.view.InsetsState.InternalInsetType;
import android.view.MagnificationSpec;
import android.view.RemoteAnimationDefinition;
@@ -515,6 +520,9 @@
private final InsetsStateController mInsetsStateController;
+ private SurfaceControl mParentSurfaceControl;
+ private InputWindowHandle mPortalWindowHandle;
+
// Last systemUiVisibility we received from status bar.
private int mLastStatusBarVisibility = 0;
// Last systemUiVisibility we dispatched to windows.
@@ -2417,10 +2425,7 @@
win.getTouchableRegion(mTmpRegion);
mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
}
- for (int i = mTapExcludeProvidingWindows.size() - 1; i >= 0; i--) {
- final WindowState win = mTapExcludeProvidingWindows.valueAt(i);
- win.amendTapExcludeRegion(mTouchExcludeRegion);
- }
+ amendWindowTapExcludeRegion(mTouchExcludeRegion);
// TODO(multi-display): Support docked stacks on secondary displays.
if (mDisplayId == DEFAULT_DISPLAY && getSplitScreenPrimaryStack() != null) {
mDividerControllerLocked.getTouchRegion(mTmpRect);
@@ -2432,6 +2437,18 @@
}
}
+ /**
+ * Union the region with all the tap exclude region provided by windows on this display.
+ *
+ * @param inOutRegion The region to be amended.
+ */
+ void amendWindowTapExcludeRegion(Region inOutRegion) {
+ for (int i = mTapExcludeProvidingWindows.size() - 1; i >= 0; i--) {
+ final WindowState win = mTapExcludeProvidingWindows.valueAt(i);
+ win.amendTapExcludeRegion(inOutRegion);
+ }
+ }
+
@Override
void switchUser() {
super.switchUser();
@@ -3593,6 +3610,13 @@
private void updateBounds() {
calculateBounds(mDisplayInfo, mTmpBounds);
setBounds(mTmpBounds);
+ if (mPortalWindowHandle != null && mParentSurfaceControl != null) {
+ mPortalWindowHandle.touchableRegion.getBounds(mTmpRect);
+ if (!mTmpBounds.equals(mTmpRect)) {
+ mPortalWindowHandle.touchableRegion.set(mTmpBounds);
+ mPendingTransaction.setInputWindowInfo(mParentSurfaceControl, mPortalWindowHandle);
+ }
+ }
}
// Determines the current display bounds based on the current state
@@ -4837,15 +4861,43 @@
|| mWmService.mForceDesktopModeOnExternalDisplays;
}
- /**
+ /**
* Re-parent the DisplayContent's top surfaces, {@link #mWindowingLayer} and
* {@link #mOverlayLayer} to the specified surfaceControl.
*
- * @param surfaceControlHandle The new SurfaceControl, where the DisplayContent's
- * surfaces will be re-parented to.
+ * @param sc The new SurfaceControl, where the DisplayContent's surfaces will be re-parented to.
*/
void reparentDisplayContent(SurfaceControl sc) {
- mPendingTransaction.reparent(mWindowingLayer, sc)
- .reparent(mOverlayLayer, sc);
+ mParentSurfaceControl = sc;
+ if (mPortalWindowHandle == null) {
+ mPortalWindowHandle = createPortalWindowHandle(sc.toString());
+ }
+ mPendingTransaction.setInputWindowInfo(sc, mPortalWindowHandle)
+ .reparent(mWindowingLayer, sc).reparent(mOverlayLayer, sc);
+ }
+
+ /**
+ * Create a portal window handle for input. This window transports any touch to the display
+ * indicated by {@link InputWindowHandle#portalToDisplayId} if the touch hits this window.
+ *
+ * @param name The name of the portal window handle.
+ * @return the new portal window handle.
+ */
+ private InputWindowHandle createPortalWindowHandle(String name) {
+ // Let surface flinger to set the display ID of this input window handle because we don't
+ // know which display the parent surface control is on.
+ final InputWindowHandle portalWindowHandle = new InputWindowHandle(
+ null /* inputApplicationHandle */, null /* clientWindow */, INVALID_DISPLAY);
+ portalWindowHandle.name = name;
+ portalWindowHandle.token = new Binder();
+ portalWindowHandle.layoutParamsFlags =
+ FLAG_SPLIT_TOUCH | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL;
+ getBounds(mTmpBounds);
+ portalWindowHandle.touchableRegion.set(mTmpBounds);
+ portalWindowHandle.scaleFactor = 1f;
+ portalWindowHandle.ownerPid = Process.myPid();
+ portalWindowHandle.ownerUid = Process.myUid();
+ portalWindowHandle.portalToDisplayId = mDisplayId;
+ return portalWindowHandle;
}
}
diff --git a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
index cbc936f..0a4ab67 100644
--- a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
+++ b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
@@ -49,7 +49,9 @@
void amendRegion(Region region, Rect boundingRegion) {
for (int i = mTapExcludeRects.size() - 1; i>= 0 ; --i) {
final Rect rect = mTapExcludeRects.valueAt(i);
- rect.intersect(boundingRegion);
+ if (boundingRegion != null) {
+ rect.intersect(boundingRegion);
+ }
region.union(rect);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index 2e5df45..dd94af6 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -70,6 +70,18 @@
// method target window will lose the focus.
return;
}
+ final Region windowTapExcludeRegion = Region.obtain();
+ mDisplayContent.amendWindowTapExcludeRegion(windowTapExcludeRegion);
+ if (windowTapExcludeRegion.contains(x, y)) {
+ windowTapExcludeRegion.recycle();
+ // The user is tapping on the window tap exclude region. We don't move this
+ // display to top. A window tap exclude region, for example, may be set by an
+ // ActivityView, and the region would match the bounds of both the ActivityView
+ // and the virtual display in it. In this case, we would take the tap that is on
+ // the embedded virtual display instead of this display.
+ return;
+ }
+ windowTapExcludeRegion.recycle();
WindowContainer parent = mDisplayContent.getParent();
if (parent != null && parent.getTopChild() != mDisplayContent) {
parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent,
@@ -81,9 +93,6 @@
@Override
public void onPointerEvent(MotionEvent motionEvent) {
- if (motionEvent.getDisplayId() != getDisplayId()) {
- return;
- }
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
final int x = (int) motionEvent.getX();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 752c24e..975e62a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6532,8 +6532,13 @@
/**
* Update a tap exclude region with a rectangular area in the window identified by the provided
- * id. Touches on this region will not switch focus to this window. Passing an empty rect will
- * remove the area from the exclude region of this window.
+ * id. Touches down on this region will not:
+ * <ol>
+ * <li>Switch focus to this window.</li>
+ * <li>Move the display of this window to top.</li>
+ * <li>Send the touch events to this window.</li>
+ * </ol>
+ * Passing an empty rect will remove the area from the exclude region of this window.
*/
void updateTapExcludeRegion(IWindow client, int regionId, int left, int top, int width,
int height) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4f12010..62e7200 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -536,7 +536,7 @@
private final Point mSurfacePosition = new Point();
/**
- * A region inside of this window to be excluded from touch-related focus switches.
+ * A region inside of this window to be excluded from touch.
*/
private TapExcludeRegionHolder mTapExcludeRegionHolder;
@@ -2168,6 +2168,24 @@
}
region.set(mTmpRect);
cropRegionToStackBoundsIfNeeded(region);
+ subtractTouchExcludeRegionIfNeeded(region);
+ } else if (modal && mTapExcludeRegionHolder != null) {
+ final Region touchExcludeRegion = Region.obtain();
+ amendTapExcludeRegion(touchExcludeRegion);
+ if (!touchExcludeRegion.isEmpty()) {
+ // Remove touch modal because there are some areas that cannot be touched.
+ flags |= FLAG_NOT_TOUCH_MODAL;
+ // Give it a large touchable region at first because it was touch modal. The window
+ // might be moved on the display, so the touchable region should be large enough to
+ // ensure it covers the whole display, no matter where it is moved.
+ getDisplayContent().getBounds(mTmpRect);
+ final int dw = mTmpRect.width();
+ final int dh = mTmpRect.height();
+ region.set(-dw, -dh, dw + dw, dh + dh);
+ // Subtract the area that cannot be touched.
+ region.op(touchExcludeRegion, Region.Op.DIFFERENCE);
+ }
+ touchExcludeRegion.recycle();
} else {
// Not modal or full screen modal
getTouchableRegion(region);
@@ -2837,6 +2855,7 @@
}
}
cropRegionToStackBoundsIfNeeded(outRegion);
+ subtractTouchExcludeRegionIfNeeded(outRegion);
}
private void cropRegionToStackBoundsIfNeeded(Region region) {
@@ -2855,6 +2874,22 @@
}
/**
+ * If this window has areas that cannot be touched, we subtract those areas from its touchable
+ * region.
+ */
+ private void subtractTouchExcludeRegionIfNeeded(Region touchableRegion) {
+ if (mTapExcludeRegionHolder == null) {
+ return;
+ }
+ final Region touchExcludeRegion = Region.obtain();
+ amendTapExcludeRegion(touchExcludeRegion);
+ if (!touchExcludeRegion.isEmpty()) {
+ touchableRegion.op(touchExcludeRegion, Region.Op.DIFFERENCE);
+ }
+ touchExcludeRegion.recycle();
+ }
+
+ /**
* Report a focus change. Must be called with no locks held, and consistently
* from the same serialized thread (such as dispatched from a handler).
*/
@@ -4728,11 +4763,25 @@
mTapExcludeRegionHolder.updateRegion(regionId, left, top, width, height);
// Trigger touch exclude region update on current display.
currentDisplay.updateTouchExcludeRegion();
+ // Trigger touchable region update for this window.
+ currentDisplay.getInputMonitor().updateInputWindowsLw(true /* force */);
}
- /** Union the region with current tap exclude region that this window provides. */
+ /**
+ * Union the region with current tap exclude region that this window provides.
+ *
+ * @param region The region to be amended. It is on the screen coordinates.
+ */
void amendTapExcludeRegion(Region region) {
- mTapExcludeRegionHolder.amendRegion(region, getBounds());
+ final Region tempRegion = Region.obtain();
+ mTmpRect.set(mWindowFrames.mFrame);
+ mTmpRect.offsetTo(0, 0);
+ mTapExcludeRegionHolder.amendRegion(tempRegion, mTmpRect);
+ // The region held by the holder is on the window coordinates. We need to translate it to
+ // the screen coordinates.
+ tempRegion.translate(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top);
+ region.op(tempRegion, Region.Op.UNION);
+ tempRegion.recycle();
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 51bdbb3..8f223b2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -74,20 +74,14 @@
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
-
import static android.provider.Telephony.Carriers.DPC_URI;
import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
- .PROVISIONING_ENTRY_POINT_ADB;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
- .STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
-
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER;
import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER;
-
-
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -240,11 +234,11 @@
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.StatLogger;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
-import com.android.internal.util.StatLogger;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
@@ -14207,7 +14201,8 @@
+ "calendar APIs", packageName));
return false;
}
- final Intent intent = new Intent(CalendarContract.ACTION_VIEW_WORK_CALENDAR_EVENT);
+ final Intent intent = new Intent(
+ CalendarContract.ACTION_VIEW_MANAGED_PROFILE_CALENDAR_EVENT);
intent.setPackage(packageName);
intent.putExtra(CalendarContract.EXTRA_EVENT_ID, eventId);
intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, start);
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
new file mode 100644
index 0000000..33cbf7a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.rollback;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.content.pm.VersionedPackage;
+import android.content.rollback.PackageRollbackInfo;
+import android.content.rollback.PackageRollbackInfo.RestoreInfo;
+import android.util.IntArray;
+
+import com.android.server.pm.Installer;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.util.ArrayList;
+
+@RunWith(JUnit4.class)
+public class AppDataRollbackHelperTest {
+
+ @Test
+ public void testSnapshotAppData() throws Exception {
+ Installer installer = mock(Installer.class);
+ AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
+
+ // All users are unlocked so we should snapshot data for them.
+ doReturn(true).when(helper).isUserCredentialLocked(eq(10));
+ doReturn(true).when(helper).isUserCredentialLocked(eq(11));
+ IntArray pending = helper.snapshotAppData("com.foo.bar", new int[]{10, 11});
+ assertEquals(2, pending.size());
+ assertEquals(10, pending.get(0));
+ assertEquals(11, pending.get(1));
+
+ InOrder inOrder = Mockito.inOrder(installer);
+ inOrder.verify(installer).snapshotAppData(
+ eq("com.foo.bar"), eq(10), eq(Installer.FLAG_STORAGE_DE));
+ inOrder.verify(installer).snapshotAppData(
+ eq("com.foo.bar"), eq(11), eq(Installer.FLAG_STORAGE_DE));
+ inOrder.verifyNoMoreInteractions();
+
+ // One of the users is unlocked but the other isn't
+ doReturn(false).when(helper).isUserCredentialLocked(eq(10));
+ doReturn(true).when(helper).isUserCredentialLocked(eq(11));
+
+ pending = helper.snapshotAppData("com.foo.bar", new int[]{10, 11});
+ assertEquals(1, pending.size());
+ assertEquals(11, pending.get(0));
+
+ inOrder = Mockito.inOrder(installer);
+ inOrder.verify(installer).snapshotAppData(
+ eq("com.foo.bar"), eq(10),
+ eq(Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE));
+ inOrder.verify(installer).snapshotAppData(
+ eq("com.foo.bar"), eq(11), eq(Installer.FLAG_STORAGE_DE));
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ private static RollbackData createInProgressRollbackData(String packageName) {
+ RollbackData data = new RollbackData(1, new File("/does/not/exist"));
+ data.packages.add(new PackageRollbackInfo(
+ new VersionedPackage(packageName, 1), new VersionedPackage(packageName, 1),
+ new IntArray(), new ArrayList<>()));
+ data.inProgress = true;
+
+ return data;
+ }
+
+ @Test
+ public void testRestoreAppDataSnapshot_noRollbackData() throws Exception {
+ Installer installer = mock(Installer.class);
+ AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
+
+ assertFalse(helper.restoreAppData("com.foo", null, 0, 0, 0, "seinfo"));
+ verifyZeroInteractions(installer);
+ }
+
+ @Test
+ public void testRestoreAppDataSnapshot_noRollbackInProgress() throws Exception {
+ Installer installer = mock(Installer.class);
+ AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
+
+ RollbackData rd = createInProgressRollbackData("com.foo");
+ // Override the in progress flag.
+ rd.inProgress = false;
+ assertFalse(helper.restoreAppData("com.foo", rd, 0, 0, 0, "seinfo"));
+ verifyZeroInteractions(installer);
+ }
+
+ @Test
+ public void testRestoreAppDataSnapshot_pendingBackupForUser() throws Exception {
+ Installer installer = mock(Installer.class);
+ AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
+
+ RollbackData rd = createInProgressRollbackData("com.foo");
+ IntArray pendingBackups = rd.packages.get(0).getPendingBackups();
+ pendingBackups.add(10);
+ pendingBackups.add(11);
+
+ assertTrue(helper.restoreAppData("com.foo", rd, 10 /* userId */, 1, 2, "seinfo"));
+
+ // Should only require FLAG_STORAGE_DE here because we have a pending backup that we
+ // didn't manage to execute.
+ InOrder inOrder = Mockito.inOrder(installer);
+ inOrder.verify(installer).restoreAppDataSnapshot(
+ eq("com.foo"), eq(1), eq(2L), eq("seinfo"), eq(10), eq(Installer.FLAG_STORAGE_DE));
+ inOrder.verifyNoMoreInteractions();
+
+ assertEquals(1, pendingBackups.size());
+ assertEquals(11, pendingBackups.get(0));
+ }
+
+ @Test
+ public void testRestoreAppDataSnapshot_availableBackupForLockedUser() throws Exception {
+ Installer installer = mock(Installer.class);
+ AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
+ doReturn(true).when(helper).isUserCredentialLocked(eq(10));
+
+ RollbackData rd = createInProgressRollbackData("com.foo");
+
+ assertTrue(helper.restoreAppData("com.foo", rd, 10 /* userId */, 1, 2, "seinfo"));
+
+ InOrder inOrder = Mockito.inOrder(installer);
+ inOrder.verify(installer).restoreAppDataSnapshot(
+ eq("com.foo"), eq(1), eq(2L), eq("seinfo"), eq(10), eq(Installer.FLAG_STORAGE_DE));
+ inOrder.verifyNoMoreInteractions();
+
+ ArrayList<RestoreInfo> pendingRestores = rd.packages.get(0).getPendingRestores();
+ assertEquals(1, pendingRestores.size());
+ assertEquals(10, pendingRestores.get(0).userId);
+ assertEquals(1, pendingRestores.get(0).appId);
+ assertEquals("seinfo", pendingRestores.get(0).seInfo);
+ }
+
+ @Test
+ public void testRestoreAppDataSnapshot_availableBackupForUnockedUser() throws Exception {
+ Installer installer = mock(Installer.class);
+ AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
+ doReturn(false).when(helper).isUserCredentialLocked(eq(10));
+
+ RollbackData rd = createInProgressRollbackData("com.foo");
+ assertFalse(helper.restoreAppData("com.foo", rd, 10 /* userId */, 1, 2, "seinfo"));
+
+ InOrder inOrder = Mockito.inOrder(installer);
+ inOrder.verify(installer).restoreAppDataSnapshot(
+ eq("com.foo"), eq(1), eq(2L), eq("seinfo"), eq(10),
+ eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
+ inOrder.verifyNoMoreInteractions();
+
+ ArrayList<RestoreInfo> pendingRestores = rd.packages.get(0).getPendingRestores();
+ assertEquals(0, pendingRestores.size());
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index bde9dde..47ec390 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2006,6 +2006,28 @@
}
@Test
+ public void testXml_statusBarIcons_default() throws Exception {
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
+ mHelper.shouldHideSilentStatusIcons());
+ }
+
+ @Test
+ public void testXml_statusBarIcons() throws Exception {
+ mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
+
+ ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+ loadStreamXml(baos, false);
+
+ assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
+ mHelper.shouldHideSilentStatusIcons());
+ }
+
+ @Test
public void testSetNotificationDelegate() {
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 4475630..3317876 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -540,7 +540,7 @@
*
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public int getDataRegState() {
return mDataRegState;
}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 86af642..c1c598d 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.content.pm.VersionedPackage;
import android.os.test.TestLooper;
import android.support.test.InstrumentationRegistry;
@@ -47,6 +48,7 @@
private static final String APP_B = "com.package.b";
private static final String APP_C = "com.package.c";
private static final String APP_D = "com.package.d";
+ private static final long VERSION_CODE = 1L;
private static final String OBSERVER_NAME_1 = "observer1";
private static final String OBSERVER_NAME_2 = "observer2";
private static final String OBSERVER_NAME_3 = "observer3";
@@ -193,7 +195,7 @@
// Then fail APP_A below the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT - 1; i++) {
- watchdog.onPackageFailure(new String[]{APP_A});
+ watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
@@ -209,12 +211,10 @@
* the failed packages.
*/
@Test
- public void testPackageFailureNotifyNone() throws Exception {
+ public void testPackageFailureDifferentPackageNotifyNone() throws Exception {
PackageWatchdog watchdog = createWatchdog();
- TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
- PackageHealthObserverImpact.USER_IMPACT_HIGH);
- TestObserver observer2 = new TestObserver(OBSERVER_NAME_2,
- PackageHealthObserverImpact.USER_IMPACT_HIGH);
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
@@ -222,7 +222,7 @@
// Then fail APP_C (not observed) above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
- watchdog.onPackageFailure(new String[]{APP_C});
+ watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
@@ -234,6 +234,40 @@
}
/**
+ * Test package failure and does not notify any observer because the failed package version
+ * does not match the available rollback-from-version.
+ */
+ @Test
+ public void testPackageFailureDifferentVersionNotifyNone() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ long differentVersionCode = 2L;
+ TestObserver observer = new TestObserver(OBSERVER_NAME_1) {
+ public int onHealthCheckFailed(String packageName, long versionCode) {
+ if (versionCode == VERSION_CODE) {
+ // Only rollback for specific versionCode
+ return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
+ }
+ return PackageHealthObserverImpact.USER_IMPACT_NONE;
+ }
+ };
+
+ watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
+
+ // Then fail APP_A (different version) above the threshold
+ for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ watchdog.onPackageFailure(Arrays.asList(
+ new VersionedPackage(APP_A, differentVersionCode)));
+ }
+
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
+ // Verify that observers are not notified
+ assertEquals(0, observer.mFailedPackages.size());
+ }
+
+
+ /**
* Test package failure and notifies only least impact observers.
*/
@Test
@@ -260,7 +294,10 @@
// Then fail all apps above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
- watchdog.onPackageFailure(new String[]{APP_A, APP_B, APP_C, APP_D});
+ watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE),
+ new VersionedPackage(APP_B, VERSION_CODE),
+ new VersionedPackage(APP_C, VERSION_CODE),
+ new VersionedPackage(APP_D, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
@@ -297,7 +334,7 @@
* <ul>
*/
@Test
- public void testPackageFailureNotifyLeastSuccessively() throws Exception {
+ public void testPackageFailureNotifyLeastImpactSuccessively() throws Exception {
PackageWatchdog watchdog = createWatchdog();
TestObserver observerFirst = new TestObserver(OBSERVER_NAME_1,
PackageHealthObserverImpact.USER_IMPACT_LOW);
@@ -310,7 +347,7 @@
// Then fail APP_A above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
- watchdog.onPackageFailure(new String[]{APP_A});
+ watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
mTestLooper.dispatchAll();
@@ -327,7 +364,7 @@
// Then fail APP_A again above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
- watchdog.onPackageFailure(new String[]{APP_A});
+ watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
mTestLooper.dispatchAll();
@@ -344,7 +381,7 @@
// Then fail APP_A again above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
- watchdog.onPackageFailure(new String[]{APP_A});
+ watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
mTestLooper.dispatchAll();
@@ -361,7 +398,7 @@
// Then fail APP_A again above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
- watchdog.onPackageFailure(new String[]{APP_A});
+ watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
mTestLooper.dispatchAll();
@@ -388,7 +425,7 @@
// Then fail APP_A above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
- watchdog.onPackageFailure(new String[]{APP_A});
+ watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
}
// Run handler so package failures are dispatched to observers
@@ -420,11 +457,11 @@
mImpact = impact;
}
- public int onHealthCheckFailed(String packageName) {
+ public int onHealthCheckFailed(String packageName, long versionCode) {
return mImpact;
}
- public boolean execute(String packageName) {
+ public boolean execute(String packageName, long versionCode) {
mFailedPackages.add(packageName);
return true;
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 036c5dc..3127d74 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -495,7 +495,7 @@
mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
"Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
- linkProperties, mScore, new NetworkMisc()) {
+ linkProperties, mScore, new NetworkMisc(), NetworkFactory.SerialNumber.NONE) {
@Override
public void unwanted() { mDisconnected.open(); }
@@ -725,7 +725,7 @@
/**
* A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove
* operations have been processed. Before ConnectivityService can add or remove any requests,
- * the factory must be told to expect those operations by calling expectAddRequests or
+ * the factory must be told to expect those operations by calling expectAddRequestsWithScores or
* expectRemoveRequests.
*/
private static class MockNetworkFactory extends NetworkFactory {
@@ -734,19 +734,22 @@
private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
// Used to expect that requests be removed or added on a separate thread, without sleeping.
- // Callers can call either expectAddRequests() or expectRemoveRequests() exactly once, then
- // cause some other thread to add or remove requests, then call waitForRequests(). We can
- // either expect requests to be added or removed, but not both, because CountDownLatch can
- // only count in one direction.
- private CountDownLatch mExpectations;
+ // Callers can call either expectAddRequestsWithScores() or expectRemoveRequests() exactly
+ // once, then cause some other thread to add or remove requests, then call
+ // waitForRequests().
+ // It is not possible to wait for both add and remove requests. When adding, the queue
+ // contains the expected score. When removing, the value is unused, all matters is the
+ // number of objects in the queue.
+ private final LinkedBlockingQueue<Integer> mExpectations;
// Whether we are currently expecting requests to be added or removed. Valid only if
- // mExpectations is non-null.
+ // mExpectations is non-empty.
private boolean mExpectingAdditions;
public MockNetworkFactory(Looper looper, Context context, String logTag,
NetworkCapabilities filter) {
super(looper, context, logTag, filter);
+ mExpectations = new LinkedBlockingQueue<>();
}
public int getMyRequestCount() {
@@ -778,69 +781,82 @@
}
@Override
- protected void handleAddRequest(NetworkRequest request, int score) {
- // If we're expecting anything, we must be expecting additions.
- if (mExpectations != null && !mExpectingAdditions) {
- fail("Can't add requests while expecting requests to be removed");
- }
+ protected void handleAddRequest(NetworkRequest request, int score,
+ int factorySerialNumber) {
+ synchronized (mExpectations) {
+ final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
- // Add the request.
- super.handleAddRequest(request, score);
+ assertNotNull("Added more requests than expected (" + request + " score : "
+ + score + ")", expectedScore);
+ // If we're expecting anything, we must be expecting additions.
+ if (!mExpectingAdditions) {
+ fail("Can't add requests while expecting requests to be removed");
+ }
+ if (expectedScore != score) {
+ fail("Expected score was " + expectedScore + " but actual was " + score
+ + " in added request");
+ }
- // Reduce the number of request additions we're waiting for.
- if (mExpectingAdditions) {
- assertTrue("Added more requests than expected", mExpectations.getCount() > 0);
- mExpectations.countDown();
+ // Add the request.
+ super.handleAddRequest(request, score, factorySerialNumber);
+ mExpectations.notify();
}
}
@Override
protected void handleRemoveRequest(NetworkRequest request) {
- // If we're expecting anything, we must be expecting removals.
- if (mExpectations != null && mExpectingAdditions) {
- fail("Can't remove requests while expecting requests to be added");
- }
+ synchronized (mExpectations) {
+ final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
- // Remove the request.
- super.handleRemoveRequest(request);
+ assertTrue("Removed more requests than expected", expectedScore != null);
+ // If we're expecting anything, we must be expecting removals.
+ if (mExpectingAdditions) {
+ fail("Can't remove requests while expecting requests to be added");
+ }
- // Reduce the number of request removals we're waiting for.
- if (!mExpectingAdditions) {
- assertTrue("Removed more requests than expected", mExpectations.getCount() > 0);
- mExpectations.countDown();
+ // Remove the request.
+ super.handleRemoveRequest(request);
+ mExpectations.notify();
}
}
private void assertNoExpectations() {
- if (mExpectations != null) {
- fail("Can't add expectation, " + mExpectations.getCount() + " already pending");
+ if (mExpectations.size() != 0) {
+ fail("Can't add expectation, " + mExpectations.size() + " already pending");
}
}
- // Expects that count requests will be added.
- public void expectAddRequests(final int count) {
+ // Expects that requests with the specified scores will be added.
+ public void expectAddRequestsWithScores(final int... scores) {
assertNoExpectations();
mExpectingAdditions = true;
- mExpectations = new CountDownLatch(count);
+ for (int score : scores) {
+ mExpectations.add(score);
+ }
}
// Expects that count requests will be removed.
public void expectRemoveRequests(final int count) {
assertNoExpectations();
mExpectingAdditions = false;
- mExpectations = new CountDownLatch(count);
+ for (int i = 0; i < count; ++i) {
+ mExpectations.add(0); // For removals the score is ignored so any value will do.
+ }
}
// Waits for the expected request additions or removals to happen within a timeout.
public void waitForRequests() throws InterruptedException {
- assertNotNull("Nothing to wait for", mExpectations);
- mExpectations.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- final long count = mExpectations.getCount();
+ final long deadline = SystemClock.elapsedRealtime() + TIMEOUT_MS;
+ synchronized (mExpectations) {
+ while (mExpectations.size() > 0 && SystemClock.elapsedRealtime() < deadline) {
+ mExpectations.wait(deadline - SystemClock.elapsedRealtime());
+ }
+ }
+ final long count = mExpectations.size();
final String msg = count + " requests still not " +
(mExpectingAdditions ? "added" : "removed") +
" after " + TIMEOUT_MS + " ms";
assertEquals(msg, 0, count);
- mExpectations = null;
}
public void waitForNetworkRequests(final int count) throws InterruptedException {
@@ -2271,6 +2287,12 @@
callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
}
+ private int[] makeIntArray(final int size, final int value) {
+ final int[] array = new int[size];
+ Arrays.fill(array, value);
+ return array;
+ }
+
private void tryNetworkFactoryRequests(int capability) throws Exception {
// Verify NOT_RESTRICTED is set appropriately
final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
@@ -2292,7 +2314,7 @@
mServiceContext, "testFactory", filter);
testFactory.setScoreFilter(40);
ConditionVariable cv = testFactory.getNetworkStartedCV();
- testFactory.expectAddRequests(1);
+ testFactory.expectAddRequestsWithScores(0);
testFactory.register();
testFactory.waitForNetworkRequests(1);
int expectedRequestCount = 1;
@@ -2303,7 +2325,7 @@
assertFalse(testFactory.getMyStartRequested());
NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
networkCallback = new NetworkCallback();
- testFactory.expectAddRequests(1);
+ testFactory.expectAddRequestsWithScores(0); // New request
mCm.requestNetwork(request, networkCallback);
expectedRequestCount++;
testFactory.waitForNetworkRequests(expectedRequestCount);
@@ -2323,7 +2345,7 @@
// When testAgent connects, ConnectivityService will re-send us all current requests with
// the new score. There are expectedRequestCount such requests, and we must wait for all of
// them.
- testFactory.expectAddRequests(expectedRequestCount);
+ testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 50));
testAgent.connect(false);
testAgent.addCapability(capability);
waitFor(cv);
@@ -2331,7 +2353,7 @@
assertFalse(testFactory.getMyStartRequested());
// Bring in a bunch of requests.
- testFactory.expectAddRequests(10);
+ testFactory.expectAddRequestsWithScores(makeIntArray(10, 50));
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
ConnectivityManager.NetworkCallback[] networkCallbacks =
new ConnectivityManager.NetworkCallback[10];
@@ -2354,8 +2376,11 @@
// Drop the higher scored network.
cv = testFactory.getNetworkStartedCV();
+ // With the default network disconnecting, the requests are sent with score 0 to factories.
+ testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 0));
testAgent.disconnect();
waitFor(cv);
+ testFactory.waitForNetworkRequests(expectedRequestCount);
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
assertTrue(testFactory.getMyStartRequested());
@@ -3177,22 +3202,23 @@
testFactory.setScoreFilter(40);
// Register the factory and expect it to start looking for a network.
- testFactory.expectAddRequests(1);
+ testFactory.expectAddRequestsWithScores(0); // Score 0 as the request is not served yet.
testFactory.register();
testFactory.waitForNetworkRequests(1);
assertTrue(testFactory.getMyStartRequested());
// Bring up wifi. The factory stops looking for a network.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
- testFactory.expectAddRequests(2); // Because the default request changes score twice.
+ // Score 60 - 40 penalty for not validated yet, then 60 when it validates
+ testFactory.expectAddRequestsWithScores(20, 60);
mWiFiNetworkAgent.connect(true);
- testFactory.waitForNetworkRequests(1);
+ testFactory.waitForRequests();
assertFalse(testFactory.getMyStartRequested());
ContentResolver cr = mServiceContext.getContentResolver();
// Turn on mobile data always on. The factory starts looking again.
- testFactory.expectAddRequests(1);
+ testFactory.expectAddRequestsWithScores(0); // Always on requests comes up with score 0
setAlwaysOnNetworks(true);
testFactory.waitForNetworkRequests(2);
assertTrue(testFactory.getMyStartRequested());
@@ -3200,7 +3226,7 @@
// Bring up cell data and check that the factory stops looking.
assertLength(1, mCm.getAllNetworks());
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
- testFactory.expectAddRequests(2); // Because the cell request changes score twice.
+ testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
testFactory.waitForNetworkRequests(2);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 9578ded..e877a8f 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -35,6 +35,7 @@
import android.net.INetd;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkMisc;
import android.net.NetworkStack;
@@ -356,7 +357,8 @@
caps.addCapability(0);
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
- caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS);
+ caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS,
+ NetworkFactory.SerialNumber.NONE);
nai.everValidated = true;
return nai;
}